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).
|
// conference (if set to true, these sounds will not be played).
|
||||||
// disableJoinLeaveSounds: false,
|
// disableJoinLeaveSounds: false,
|
||||||
|
|
||||||
|
// Disables the sounds that play when a chat message is received.
|
||||||
|
// disableIncomingMessageSound: false,
|
||||||
|
|
||||||
// Information for the chrome extension banner
|
// Information for the chrome extension banner
|
||||||
// chromeExtensionBanner: {
|
// chromeExtensionBanner: {
|
||||||
// // The chrome extension to be installed address
|
// // The chrome extension to be installed address
|
||||||
|
|
|
@ -174,7 +174,7 @@ var interfaceConfig = {
|
||||||
RECENT_LIST_ENABLED: true,
|
RECENT_LIST_ENABLED: true,
|
||||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
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
|
* Specify which sharing features should be displayed. If the value is not set
|
||||||
|
|
|
@ -744,6 +744,7 @@
|
||||||
"devices": "Devices",
|
"devices": "Devices",
|
||||||
"followMe": "Everyone follows me",
|
"followMe": "Everyone follows me",
|
||||||
"framesPerSecond": "frames-per-second",
|
"framesPerSecond": "frames-per-second",
|
||||||
|
"incomingMessage": "Incoming message",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"loggedIn": "Logged in as {{name}}",
|
"loggedIn": "Logged in as {{name}}",
|
||||||
"microphones": "Microphones",
|
"microphones": "Microphones",
|
||||||
|
@ -751,13 +752,18 @@
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"noDevice": "None",
|
"noDevice": "None",
|
||||||
|
"participantJoined": "Participant Joined",
|
||||||
|
"participantLeft": "Participant Left",
|
||||||
|
"playSounds": "Play sound on",
|
||||||
"sameAsSystem": "Same as system ({{label}})",
|
"sameAsSystem": "Same as system ({{label}})",
|
||||||
"selectAudioOutput": "Audio output",
|
"selectAudioOutput": "Audio output",
|
||||||
"selectCamera": "Camera",
|
"selectCamera": "Camera",
|
||||||
"selectMic": "Microphone",
|
"selectMic": "Microphone",
|
||||||
|
"sounds": "Sounds",
|
||||||
"speakers": "Speakers",
|
"speakers": "Speakers",
|
||||||
"startAudioMuted": "Everyone starts muted",
|
"startAudioMuted": "Everyone starts muted",
|
||||||
"startVideoMuted": "Everyone starts hidden",
|
"startVideoMuted": "Everyone starts hidden",
|
||||||
|
"talkWhileMuted": "Talk while muted",
|
||||||
"title": "Settings"
|
"title": "Settings"
|
||||||
},
|
},
|
||||||
"settingsView": {
|
"settingsView": {
|
||||||
|
|
|
@ -87,6 +87,7 @@ export default [
|
||||||
'disableH264',
|
'disableH264',
|
||||||
'disableHPF',
|
'disableHPF',
|
||||||
'disableInviteFunctions',
|
'disableInviteFunctions',
|
||||||
|
'disableIncomingMessageSound',
|
||||||
'disableJoinLeaveSounds',
|
'disableJoinLeaveSounds',
|
||||||
'disableLocalVideoFlip',
|
'disableLocalVideoFlip',
|
||||||
'disableNS',
|
'disableNS',
|
||||||
|
|
|
@ -371,6 +371,7 @@ function _localParticipantLeft({ dispatch }, next, action) {
|
||||||
function _maybePlaySounds({ getState, dispatch }, action) {
|
function _maybePlaySounds({ getState, dispatch }, action) {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { startAudioMuted, disableJoinLeaveSounds } = state['features/base/config'];
|
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 we have join/leave sounds disabled, don't play anything.
|
||||||
if (disableJoinLeaveSounds) {
|
if (disableJoinLeaveSounds) {
|
||||||
|
@ -387,13 +388,16 @@ function _maybePlaySounds({ getState, dispatch }, action) {
|
||||||
const { isReplacing, isReplaced } = action.participant;
|
const { isReplacing, isReplaced } = action.participant;
|
||||||
|
|
||||||
if (action.type === PARTICIPANT_JOINED) {
|
if (action.type === PARTICIPANT_JOINED) {
|
||||||
|
if (!joinSound) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { presence } = action.participant;
|
const { presence } = action.participant;
|
||||||
|
|
||||||
// The sounds for the poltergeist are handled by features/invite.
|
// The sounds for the poltergeist are handled by features/invite.
|
||||||
if (presence !== INVITED && presence !== CALLING && !isReplacing) {
|
if (presence !== INVITED && presence !== CALLING && !isReplacing) {
|
||||||
dispatch(playSound(PARTICIPANT_JOINED_SOUND_ID));
|
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));
|
dispatch(playSound(PARTICIPANT_LEFT_SOUND_ID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ const DEFAULT_STATE = {
|
||||||
micDeviceId: undefined,
|
micDeviceId: undefined,
|
||||||
serverURL: undefined,
|
serverURL: undefined,
|
||||||
hideShareAudioHelper: false,
|
hideShareAudioHelper: false,
|
||||||
|
soundsIncomingMessage: true,
|
||||||
|
soundsParticipantJoined: true,
|
||||||
|
soundsParticipantLeft: true,
|
||||||
|
soundsTalkWhileMuted: true,
|
||||||
startAudioOnly: false,
|
startAudioOnly: false,
|
||||||
startWithAudioMuted: false,
|
startWithAudioMuted: false,
|
||||||
startWithVideoMuted: false,
|
startWithVideoMuted: false,
|
||||||
|
|
|
@ -305,8 +305,10 @@ function _handleReceivedMessage({ dispatch, getState },
|
||||||
// Logic for all platforms:
|
// Logic for all platforms:
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { isOpen: isChatOpen } = state['features/chat'];
|
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));
|
dispatch(playSound(INCOMING_MSG_SOUND_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
SET_VIDEO_SETTINGS_VISIBILITY
|
SET_VIDEO_SETTINGS_VISIBILITY
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import { LogoutDialog, SettingsDialog } from './components';
|
import { LogoutDialog, SettingsDialog } from './components';
|
||||||
import { getMoreTabProps, getProfileTabProps } from './functions';
|
import { getMoreTabProps, getProfileTabProps, getSoundsTabProps } from './functions';
|
||||||
|
|
||||||
declare var APP: Object;
|
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.
|
* Toggles the visibility of the audio settings.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,13 +11,14 @@ import {
|
||||||
getDeviceSelectionDialogProps,
|
getDeviceSelectionDialogProps,
|
||||||
submitDeviceSelectionTab
|
submitDeviceSelectionTab
|
||||||
} from '../../../device-selection';
|
} from '../../../device-selection';
|
||||||
import { submitMoreTab, submitProfileTab } from '../../actions';
|
import { submitMoreTab, submitProfileTab, submitSoundsTab } from '../../actions';
|
||||||
import { SETTINGS_TABS } from '../../constants';
|
import { SETTINGS_TABS } from '../../constants';
|
||||||
import { getMoreTabProps, getProfileTabProps } from '../../functions';
|
import { getMoreTabProps, getProfileTabProps, getSoundsTabProps } from '../../functions';
|
||||||
|
|
||||||
import CalendarTab from './CalendarTab';
|
import CalendarTab from './CalendarTab';
|
||||||
import MoreTab from './MoreTab';
|
import MoreTab from './MoreTab';
|
||||||
import ProfileTab from './ProfileTab';
|
import ProfileTab from './ProfileTab';
|
||||||
|
import SoundsTab from './SoundsTab';
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
declare var interfaceConfig: Object;
|
declare var interfaceConfig: Object;
|
||||||
|
@ -135,6 +136,7 @@ function _mapStateToProps(state) {
|
||||||
= configuredTabs.includes('profile') && !state['features/base/config'].disableProfile;
|
= configuredTabs.includes('profile') && !state['features/base/config'].disableProfile;
|
||||||
const showCalendarSettings
|
const showCalendarSettings
|
||||||
= configuredTabs.includes('calendar') && isCalendarEnabled(state);
|
= configuredTabs.includes('calendar') && isCalendarEnabled(state);
|
||||||
|
const showSoundsSettings = configuredTabs.includes('sounds');
|
||||||
const tabs = [];
|
const tabs = [];
|
||||||
|
|
||||||
if (showDeviceSettings) {
|
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) {
|
if (showModeratorSettings || showLanguageSettings || showPrejoinSettings) {
|
||||||
tabs.push({
|
tabs.push({
|
||||||
name: SETTINGS_TABS.MORE,
|
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',
|
CALENDAR: 'calendar_tab',
|
||||||
DEVICES: 'devices_tab',
|
DEVICES: 'devices_tab',
|
||||||
MORE: 'more_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
|
* Returns a promise which resolves with a list of objects containing
|
||||||
* all the video jitsiTracks and appropriate errors for the given device ids.
|
* 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))
|
customActionHandler: () => dispatch(setAudioMuted(false))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
dispatch(playSound(TALK_WHILE_MUTED_SOUND_ID));
|
const { soundsTalkWhileMuted } = getState()['features/base/settings'];
|
||||||
|
|
||||||
|
if (soundsTalkWhileMuted) {
|
||||||
|
dispatch(playSound(TALK_WHILE_MUTED_SOUND_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (notification) {
|
if (notification) {
|
||||||
// we store the last start muted notification id that we showed,
|
// we store the last start muted notification id that we showed,
|
||||||
|
|
Loading…
Reference in New Issue