2018-04-12 19:58:20 +00:00
|
|
|
// @flow
|
2019-03-19 17:35:36 +00:00
|
|
|
|
2020-05-01 19:48:08 +00:00
|
|
|
import { jitsiLocalStorage } from 'js-utils';
|
2019-03-19 17:35:36 +00:00
|
|
|
import { randomHexString } from 'js-utils/random';
|
2018-04-12 19:58:20 +00:00
|
|
|
import _ from 'lodash';
|
|
|
|
|
2018-07-11 09:42:43 +00:00
|
|
|
import { APP_WILL_MOUNT } from '../app';
|
2019-04-04 15:10:01 +00:00
|
|
|
import { browser } from '../lib-jitsi-meet';
|
2018-04-12 19:58:20 +00:00
|
|
|
import { ReducerRegistry } from '../redux';
|
|
|
|
import { PersistenceRegistry } from '../storage';
|
2019-03-19 17:35:36 +00:00
|
|
|
import { assignIfDefined } from '../util';
|
2018-04-12 19:58:20 +00:00
|
|
|
|
|
|
|
import { SETTINGS_UPDATED } from './actionTypes';
|
2019-08-21 14:50:00 +00:00
|
|
|
import logger from './logger';
|
2018-04-12 19:58:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The default/initial redux state of the feature {@code base/settings}.
|
|
|
|
*
|
|
|
|
* @type Object
|
|
|
|
*/
|
|
|
|
const DEFAULT_STATE = {
|
|
|
|
audioOutputDeviceId: undefined,
|
|
|
|
avatarID: undefined,
|
|
|
|
avatarURL: undefined,
|
|
|
|
cameraDeviceId: undefined,
|
2019-10-18 14:30:59 +00:00
|
|
|
disableCallIntegration: undefined,
|
2020-05-07 21:05:48 +00:00
|
|
|
disableCrashReporting: undefined,
|
2019-10-18 14:30:59 +00:00
|
|
|
disableP2P: undefined,
|
2018-04-12 19:58:20 +00:00
|
|
|
displayName: undefined,
|
|
|
|
email: undefined,
|
|
|
|
localFlipX: true,
|
|
|
|
micDeviceId: undefined,
|
|
|
|
serverURL: undefined,
|
|
|
|
startAudioOnly: false,
|
|
|
|
startWithAudioMuted: false,
|
2019-05-01 14:13:25 +00:00
|
|
|
startWithVideoMuted: false,
|
|
|
|
userSelectedAudioOutputDeviceId: undefined,
|
|
|
|
userSelectedCameraDeviceId: undefined,
|
2019-05-07 08:53:01 +00:00
|
|
|
userSelectedMicDeviceId: undefined,
|
|
|
|
userSelectedAudioOutputDeviceLabel: undefined,
|
|
|
|
userSelectedCameraDeviceLabel: undefined,
|
2020-05-07 07:42:55 +00:00
|
|
|
userSelectedMicDeviceLabel: undefined,
|
|
|
|
userSelectedSkipPrejoin: undefined
|
2018-04-12 19:58:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const STORE_NAME = 'features/base/settings';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets up the persistence of the feature {@code base/settings}.
|
|
|
|
*/
|
2019-05-01 14:13:25 +00:00
|
|
|
const filterSubtree = {};
|
|
|
|
|
|
|
|
// start with the default state
|
|
|
|
Object.keys(DEFAULT_STATE).forEach(key => {
|
|
|
|
filterSubtree[key] = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
// we want to filter these props, to not be stored as they represent
|
|
|
|
// what is currently opened/used as devices
|
|
|
|
filterSubtree.audioOutputDeviceId = false;
|
|
|
|
filterSubtree.cameraDeviceId = false;
|
|
|
|
filterSubtree.micDeviceId = false;
|
|
|
|
|
|
|
|
PersistenceRegistry.register(STORE_NAME, filterSubtree);
|
2018-04-12 19:58:20 +00:00
|
|
|
|
|
|
|
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
|
|
|
switch (action.type) {
|
|
|
|
case APP_WILL_MOUNT:
|
|
|
|
return _initSettings(state);
|
|
|
|
|
|
|
|
case SETTINGS_UPDATED:
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
...action.settings
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves the legacy profile values regardless of it's being in pre or
|
|
|
|
* post-flattening format.
|
|
|
|
*
|
2018-11-08 12:25:02 +00:00
|
|
|
* FIXME: Let's remove this after a predefined time (e.g. By July 2018) to avoid
|
2018-04-12 19:58:20 +00:00
|
|
|
* garbage in the source.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
function _getLegacyProfile() {
|
2020-05-01 19:48:08 +00:00
|
|
|
let persistedProfile = jitsiLocalStorage.getItem('features/base/profile');
|
2018-04-12 19:58:20 +00:00
|
|
|
|
|
|
|
if (persistedProfile) {
|
|
|
|
try {
|
|
|
|
persistedProfile = JSON.parse(persistedProfile);
|
|
|
|
|
|
|
|
if (persistedProfile && typeof persistedProfile === 'object') {
|
|
|
|
const preFlattenedProfile = persistedProfile.profile;
|
|
|
|
|
|
|
|
return preFlattenedProfile || persistedProfile;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
logger.warn('Error parsing persisted legacy profile', e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inits the settings object based on what information we have available.
|
|
|
|
* Info taken into consideration:
|
|
|
|
* - Old Settings.js style data
|
|
|
|
* - Things that we stored in profile earlier but belong here.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {Object} featureState - The current state of the feature.
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
function _initSettings(featureState) {
|
|
|
|
let settings = featureState;
|
|
|
|
|
|
|
|
// Old Settings.js values
|
2019-06-05 00:42:48 +00:00
|
|
|
// FIXME: jibri uses old settings.js local storage values to set its display
|
|
|
|
// name and email. Provide another way for jibri to set these values, update
|
|
|
|
// jibri, and remove the old settings.js values.
|
2020-05-01 19:48:08 +00:00
|
|
|
const savedDisplayName = jitsiLocalStorage.getItem('displayname');
|
|
|
|
const savedEmail = jitsiLocalStorage.getItem('email');
|
|
|
|
let avatarID = _.escape(jitsiLocalStorage.getItem('avatarId'));
|
2018-04-12 19:58:20 +00:00
|
|
|
|
2019-06-05 00:42:48 +00:00
|
|
|
// The helper _.escape will convert null to an empty strings. The empty
|
|
|
|
// string will be saved in settings. On app re-load, because an empty string
|
|
|
|
// is a defined value, it will override any value found in local storage.
|
|
|
|
// The workaround is sidestepping _.escape when the value is not set in
|
|
|
|
// local storage.
|
|
|
|
const displayName
|
|
|
|
= savedDisplayName === null ? undefined : _.escape(savedDisplayName);
|
|
|
|
const email = savedEmail === null ? undefined : _.escape(savedEmail);
|
|
|
|
|
2018-04-12 19:58:20 +00:00
|
|
|
if (!avatarID) {
|
|
|
|
// if there is no avatar id, we generate a unique one and use it forever
|
|
|
|
avatarID = randomHexString(32);
|
|
|
|
}
|
|
|
|
|
|
|
|
settings = assignIfDefined({
|
|
|
|
avatarID,
|
|
|
|
displayName,
|
|
|
|
email
|
|
|
|
}, settings);
|
|
|
|
|
|
|
|
if (!browser.isReactNative()) {
|
|
|
|
// Browser only
|
2020-05-01 19:48:08 +00:00
|
|
|
const localFlipX = JSON.parse(jitsiLocalStorage.getItem('localFlipX') || 'true');
|
|
|
|
const cameraDeviceId = jitsiLocalStorage.getItem('cameraDeviceId') || '';
|
|
|
|
const micDeviceId = jitsiLocalStorage.getItem('micDeviceId') || '';
|
2018-04-12 19:58:20 +00:00
|
|
|
|
|
|
|
// Currently audio output device change is supported only in Chrome and
|
|
|
|
// default output always has 'default' device ID
|
2020-05-01 19:48:08 +00:00
|
|
|
const audioOutputDeviceId = jitsiLocalStorage.getItem('audioOutputDeviceId') || 'default';
|
2018-04-12 19:58:20 +00:00
|
|
|
|
2018-07-13 17:04:09 +00:00
|
|
|
settings = assignIfDefined({
|
|
|
|
audioOutputDeviceId,
|
|
|
|
cameraDeviceId,
|
|
|
|
localFlipX,
|
|
|
|
micDeviceId
|
|
|
|
}, settings);
|
2018-04-12 19:58:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Things we stored in profile earlier
|
|
|
|
const legacyProfile = _getLegacyProfile();
|
|
|
|
|
|
|
|
settings = assignIfDefined(legacyProfile, settings);
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
}
|