Persist various things in localstorage.

master
Håvar Aambø Fosstveit 2019-04-05 21:47:16 +02:00
parent e5026284fa
commit 67b3427485
17 changed files with 127 additions and 278 deletions

View File

@ -8,7 +8,6 @@ import hark from 'hark';
import ScreenShare from './ScreenShare';
import Spotlights from './Spotlights';
import { getSignalingUrl } from './urlFactory';
import * as cookiesManager from './cookiesManager';
import * as requestActions from './actions/requestActions';
import * as stateActions from './actions/stateActions';
const {
@ -52,11 +51,11 @@ export default class RoomClient
}
constructor(
{ roomId, peerName, displayName, device, useSimulcast, produce })
{ roomId, peerName, device, useSimulcast, produce })
{
logger.debug(
'constructor() [roomId:"%s", peerName:"%s", displayName:"%s", device:%s]',
roomId, peerName, displayName, device.flag);
'constructor() [roomId:"%s", peerName:"%s", device:%s]',
roomId, peerName, device.flag);
this._signalingUrl = getSignalingUrl(peerName, roomId);
@ -81,9 +80,6 @@ export default class RoomClient
// My peer name.
this._peerName = peerName;
// My display name
this._displayName = displayName;
// Alert sound
this._soundAlert = new Audio('/sounds/notify.mp3');
@ -140,8 +136,6 @@ export default class RoomClient
this._screenSharingProducer = null;
this._startKeyListener();
this.join();
}
close()
@ -309,9 +303,6 @@ export default class RoomClient
{
logger.debug('changeDisplayName() [displayName:"%s"]', displayName);
// Store in cookie.
cookiesManager.setUser({ displayName });
try
{
await this.sendRequest('change-display-name', { displayName });
@ -450,7 +441,7 @@ export default class RoomClient
if (existingTorrent)
{
const { displayName, picture } = store.getState().me;
const { displayName, picture } = store.getState().settings;
const file = {
magnetUri : existingTorrent.magnetURI,
@ -467,7 +458,7 @@ export default class RoomClient
'Torrent successfully created'
);
const { displayName, picture } = store.getState().me;
const { displayName, picture } = store.getState().settings;
const file = {
magnetUri : newTorrent.magnetURI,
displayName,
@ -698,9 +689,6 @@ export default class RoomClient
{
logger.debug('enableWebcam()');
// Store in cookie.
cookiesManager.setVideoEnabled({ webcamEnabled: true });
store.dispatch(stateActions.setWebcamInProgress(true));
try
@ -737,9 +725,6 @@ export default class RoomClient
{
logger.debug('disableWebcam()');
// Store in cookie.
cookiesManager.setVideoEnabled({ webcamEnabled: false });
store.dispatch(stateActions.setWebcamInProgress(true));
try
@ -820,8 +805,6 @@ export default class RoomClient
stateActions.setProducerTrack(this._micProducer.id, newTrack));
store.dispatch(stateActions.setSelectedAudioDevice(deviceId));
cookiesManager.setAudioDevice({ audioDeviceId: deviceId });
await this._updateAudioDevices();
}
@ -874,8 +857,6 @@ export default class RoomClient
store.dispatch(stateActions.setSelectedWebcamDevice(deviceId));
cookiesManager.setVideoDevice({ videoDeviceId: deviceId });
await this._updateWebcams();
}
catch (error)
@ -980,30 +961,6 @@ export default class RoomClient
stateActions.setMyRaiseHandStateInProgress(false));
}
async restartIce()
{
logger.debug('restartIce()');
store.dispatch(
stateActions.setRestartIceInProgress(true));
try
{
await this._room.restartIce();
}
catch (error)
{
logger.error('restartIce() failed: %o', error);
}
// Make it artificially longer.
setTimeout(() =>
{
store.dispatch(
stateActions.setRestartIceInProgress(false));
}, 500);
}
async resumeAudio()
{
logger.debug('resumeAudio()');
@ -1287,10 +1244,12 @@ export default class RoomClient
try
{
const { displayName } = store.getState().settings;
await this._room.join(
this._peerName,
{
displayName : this._displayName,
displayName : displayName,
device : this._device
}
);
@ -1336,14 +1295,8 @@ export default class RoomClient
if (this._room.canSend('audio'))
await this._setMicProducer();
// Add our webcam (unless the cookie says no).
if (this._room.canSend('video'))
{
const devicesCookie = cookiesManager.getVideoEnabled();
if (!devicesCookie || devicesCookie.webcamEnabled)
await this.enableWebcam();
}
await this.enableWebcam();
}
store.dispatch(stateActions.setRoomState('connected'));
@ -1472,8 +1425,6 @@ export default class RoomClient
}));
store.dispatch(stateActions.setSelectedAudioDevice(deviceId));
cookiesManager.setAudioDevice({ audioDeviceId: deviceId });
await this._updateAudioDevices();
@ -1732,8 +1683,6 @@ export default class RoomClient
store.dispatch(stateActions.setSelectedWebcamDevice(deviceId));
cookiesManager.setVideoDevice({ videoDeviceId: deviceId });
await this._updateWebcams();
producer.on('close', (originator) =>
@ -1856,16 +1805,10 @@ export default class RoomClient
await this._updateAudioDevices();
const devicesCookie = cookiesManager.getAudioDevice();
const { selectedAudioDevice } = store.getState().settings;
if (
devicesCookie &&
devicesCookie.audioDeviceId &&
this._audioDevices[devicesCookie.audioDeviceId]
)
{
return this._audioDevices[devicesCookie.audioDeviceId].deviceId;
}
if (selectedAudioDevice && this._audioDevices[selectedAudioDevice])
return selectedAudioDevice;
else
{
const audioDevices = Object.values(this._audioDevices);
@ -1889,16 +1832,10 @@ export default class RoomClient
await this._updateWebcams();
const devicesCookie = cookiesManager.getVideoDevice();
const { selectedWebcam } = store.getState().settings;
if (
devicesCookie &&
devicesCookie.videoDeviceId &&
this._webcams[devicesCookie.videoDeviceId]
)
{
return this._webcams[devicesCookie.videoDeviceId].deviceId;
}
if (selectedWebcam && this._webcams[selectedWebcam])
return selectedWebcam;
else
{
const webcams = Object.values(this._webcams);

View File

@ -57,11 +57,11 @@ export const setSettingsOpen = ({ settingsOpen }) =>
payload : { settingsOpen }
});
export const setMe = ({ peerName, displayName, displayNameSet, device, loginEnabled }) =>
export const setMe = ({ peerName, device, loginEnabled }) =>
{
return {
type : 'SET_ME',
payload : { peerName, displayName, displayNameSet, device, loginEnabled }
payload : { peerName, device, loginEnabled }
};
};
@ -142,22 +142,6 @@ export const setDisplayMode = (mode) =>
payload : { mode }
});
export const setAudioOnlyState = (enabled) =>
{
return {
type : 'SET_AUDIO_ONLY_STATE',
payload : { enabled }
};
};
export const setAudioOnlyInProgress = (flag) =>
{
return {
type : 'SET_AUDIO_ONLY_IN_PROGRESS',
payload : { flag }
};
};
export const setPeerVideoInProgress = (peerName, flag) =>
{
return {
@ -242,14 +226,6 @@ export const setPeerRaiseHandState = (peerName, raiseHandState) =>
};
};
export const setRestartIceInProgress = (flag) =>
{
return {
type : 'SET_RESTART_ICE_IN_PROGRESS',
payload : { flag }
};
};
export const addProducer = (producer) =>
{
return {

View File

@ -47,6 +47,7 @@ const Me = (props) =>
const {
roomClient,
me,
settings,
activeSpeaker,
style,
advancedMode,
@ -83,6 +84,7 @@ const Me = (props) =>
isMe
advancedMode={advancedMode}
peer={me}
displayName={settings.displayName}
showPeerInfo
videoTrack={webcamProducer ? webcamProducer.track : null}
videoVisible={videoVisible}
@ -121,6 +123,7 @@ Me.propTypes =
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
me : appPropTypes.Me.isRequired,
settings : PropTypes.object,
activeSpeaker : PropTypes.bool,
micProducer : appPropTypes.Producer,
webcamProducer : appPropTypes.Producer,
@ -134,6 +137,7 @@ const mapStateToProps = (state) =>
return {
me : state.me,
...meProducersSelector(state),
settings : state.settings,
activeSpeaker : state.me.name === state.room.activeSpeakerName
};
};
@ -148,6 +152,7 @@ export default withRoomContext(connect(
return (
prev.me === next.me &&
prev.producers === next.producers &&
prev.settings === next.settings &&
prev.room.activeSpeakerName === next.room.activeSpeakerName
);
}

View File

@ -287,6 +287,7 @@ const Peer = (props) =>
<VideoView
advancedMode={advancedMode}
peer={peer}
displayName={peer.displayName}
showPeerInfo
videoTrack={webcamConsumer ? webcamConsumer.track : null}
videoVisible={videoVisible}

View File

@ -122,8 +122,8 @@ ChatInput.propTypes =
const mapStateToProps = (state) =>
({
displayName : state.me.displayName,
picture : state.me.picture
displayName : state.settings.displayName,
picture : state.settings.picture
});
export default withRoomContext(
@ -135,8 +135,8 @@ export default withRoomContext(
areStatesEqual : (next, prev) =>
{
return (
prev.me.displayName === next.me.displayName &&
prev.me.picture === next.me.picture
prev.settings.displayName === next.settings.displayName &&
prev.settings.picture === next.settings.picture
);
}
}

View File

@ -75,10 +75,11 @@ const ListMe = (props) =>
{
const {
me,
settings,
classes
} = props;
const picture = me.picture || EmptyAvatar;
const picture = settings.picture || EmptyAvatar;
return (
<li className={classes.root}>
@ -86,7 +87,7 @@ const ListMe = (props) =>
<img alt='My avatar' className={classes.avatar} src={picture} />
<div className={classes.peerInfo}>
{me.displayName}
{settings.displayName}
</div>
<div className={classes.indicators}>
@ -102,12 +103,14 @@ const ListMe = (props) =>
ListMe.propTypes =
{
me : appPropTypes.Me.isRequired,
classes : PropTypes.object.isRequired
me : appPropTypes.Me.isRequired,
settings : PropTypes.object.isRequired,
classes : PropTypes.object.isRequired
};
const mapStateToProps = (state) => ({
me : state.me
me : state.me,
settings : state.settings
});
export default connect(
@ -118,7 +121,8 @@ export default connect(
areStatesEqual : (next, prev) =>
{
return (
prev.me === next.me
prev.me === next.me &&
prev.settings === next.settings
);
}
}

View File

@ -176,6 +176,10 @@ class Room extends React.PureComponent
componentDidMount()
{
const { roomClient } = this.props;
roomClient.join();
if (this.fullscreen.fullscreenEnabled)
{
this.fullscreen.addEventListener('fullscreenchange', this.handleFullscreenChange);
@ -220,6 +224,7 @@ class Room extends React.PureComponent
const {
roomClient,
room,
advancedMode,
myPicture,
loggedIn,
loginEnabled,
@ -277,9 +282,9 @@ class Room extends React.PureComponent
This website uses cookies to enhance the user experience.
</CookieConsent>
<FullScreenView advancedMode={room.advancedMode} />
<FullScreenView advancedMode={advancedMode} />
<VideoWindow advancedMode={room.advancedMode} />
<VideoWindow advancedMode={advancedMode} />
<AudioPeers />
@ -377,7 +382,7 @@ class Room extends React.PureComponent
</Hidden>
</nav>
<View advancedMode={room.advancedMode} />
<View advancedMode={advancedMode} />
<Sidebar />
@ -392,6 +397,7 @@ Room.propTypes =
{
roomClient : PropTypes.object.isRequired,
room : appPropTypes.Room.isRequired,
advancedMode : PropTypes.bool.isRequired,
myPicture : PropTypes.string,
loggedIn : PropTypes.bool.isRequired,
loginEnabled : PropTypes.bool.isRequired,
@ -407,6 +413,7 @@ Room.propTypes =
const mapStateToProps = (state) =>
({
room : state.room,
advancedMode : state.settings.advancedMode,
loggedIn : state.me.loggedIn,
loginEnabled : state.me.loginEnabled,
myPicture : state.me.picture,
@ -445,7 +452,8 @@ export default withRoomContext(connect(
prev.me.picture === next.me.picture &&
prev.toolarea.toolAreaOpen === next.toolarea.toolAreaOpen &&
prev.toolarea.unreadMessages === next.toolarea.unreadMessages &&
prev.toolarea.unreadFiles === next.toolarea.unreadFiles
prev.toolarea.unreadFiles === next.toolarea.unreadFiles &&
prev.settings.advancedMode === next.settings.advancedMode
);
}
}

View File

@ -63,6 +63,7 @@ const Settings = ({
roomClient,
room,
me,
settings,
onToggleAdvancedMode,
// handleChangeMode,
handleCloseSettings,
@ -96,7 +97,7 @@ const Settings = ({
<form className={classes.setting} autoComplete='off'>
<FormControl className={classes.formControl}>
<Select
value={me.selectedWebcam || ''}
value={settings.selectedWebcam || ''}
onChange={(event) =>
{
if (event.target.value)
@ -127,7 +128,7 @@ const Settings = ({
<form className={classes.setting} autoComplete='off'>
<FormControl className={classes.formControl}>
<Select
value={me.selectedAudioDevice || ''}
value={settings.selectedAudioDevice || ''}
onChange={(event) =>
{
if (event.target.value)
@ -157,7 +158,7 @@ const Settings = ({
</form>
<FormControlLabel
className={classes.setting}
control={<Checkbox checked={room.advancedMode} onChange={onToggleAdvancedMode} value='advancedMode' />}
control={<Checkbox checked={settings.advancedMode} onChange={onToggleAdvancedMode} value='advancedMode' />}
label='Advanced mode'
/>
{ /* <form className={classes.setting} autoComplete='off'>
@ -195,6 +196,7 @@ Settings.propTypes =
roomClient : PropTypes.any.isRequired,
me : appPropTypes.Me.isRequired,
room : appPropTypes.Room.isRequired,
settings : PropTypes.object.isRequired,
onToggleAdvancedMode : PropTypes.func.isRequired,
handleChangeMode : PropTypes.func.isRequired,
handleCloseSettings : PropTypes.func.isRequired,
@ -204,8 +206,9 @@ Settings.propTypes =
const mapStateToProps = (state) =>
{
return {
me : state.me,
room : state.room
me : state.me,
room : state.room,
settings : state.settings
};
};
@ -224,7 +227,8 @@ export default withRoomContext(connect(
{
return (
prev.me === next.me &&
prev.room === next.room
prev.room === next.room &&
prev.settings === next.settings
);
}
}

View File

@ -160,6 +160,7 @@ class VideoView extends React.PureComponent
const {
isMe,
peer,
displayName,
showPeerInfo,
videoContain,
advancedMode,
@ -206,8 +207,8 @@ class VideoView extends React.PureComponent
<div className={classes.peer}>
{ isMe ?
<EditableInput
value={peer.displayName}
propName='displayName'
value={displayName}
propName='newDisplayName'
className={classnames(classes.displayNameEdit, 'display-name')}
classLoading='loading'
classInvalid='invalid'
@ -217,11 +218,11 @@ class VideoView extends React.PureComponent
autoCorrect : false,
spellCheck : false
}}
onChange={({ displayName }) => onChangeDisplayName(displayName)}
onChange={({ newDisplayName }) => onChangeDisplayName(newDisplayName)}
/>
:
<span className={classes.displayNameStatic}>
{peer.displayName}
{displayName}
</span>
}
@ -336,6 +337,7 @@ VideoView.propTypes =
isMe : PropTypes.bool,
peer : PropTypes.oneOfType(
[ appPropTypes.Me, appPropTypes.Peer ]),
displayName : PropTypes.string,
showPeerInfo : PropTypes.bool,
videoContain : PropTypes.bool,
advancedMode : PropTypes.bool,

View File

@ -17,16 +17,11 @@ export const Device = PropTypes.shape(
export const Me = PropTypes.shape(
{
name : PropTypes.string.isRequired,
displayName : PropTypes.string,
displayNameSet : PropTypes.bool.isRequired,
device : Device.isRequired,
canSendMic : PropTypes.bool.isRequired,
canSendWebcam : PropTypes.bool.isRequired,
webcamInProgress : PropTypes.bool.isRequired,
audioOnly : PropTypes.bool.isRequired,
audioOnlyInProgress : PropTypes.bool.isRequired,
restartIceInProgress : PropTypes.bool.isRequired
name : PropTypes.string.isRequired,
device : Device.isRequired,
canSendMic : PropTypes.bool.isRequired,
canSendWebcam : PropTypes.bool.isRequired,
webcamInProgress : PropTypes.bool.isRequired
});
export const Producer = PropTypes.shape(

View File

@ -1,47 +0,0 @@
import jsCookie from 'js-cookie';
const USER_COOKIE = 'multiparty-meeting.user';
const VIDEO_COOKIE = 'multiparty-meeting.videoEnabled';
const AUDIO_DEVICE = 'multiparty-meeting.audioDevice';
const VIDEO_DEVICE = 'multiparty-meeting.videoDevice';
export function getUser()
{
return jsCookie.getJSON(USER_COOKIE);
}
export function setUser({ displayName })
{
jsCookie.set(USER_COOKIE, { displayName });
}
export function getVideoEnabled()
{
return jsCookie.getJSON(VIDEO_COOKIE);
}
export function setVideoEnabled({ webcamEnabled })
{
jsCookie.set(VIDEO_COOKIE, { webcamEnabled });
}
export function getAudioDevice()
{
return jsCookie.getJSON(AUDIO_DEVICE);
}
export function setAudioDevice({ audioDeviceId })
{
jsCookie.set(AUDIO_DEVICE, { audioDeviceId });
}
export function getVideoDevice()
{
return jsCookie.getJSON(VIDEO_DEVICE);
}
export function setVideoDevice({ videoDeviceId })
{
jsCookie.set(VIDEO_DEVICE, { videoDeviceId });
}

View File

@ -9,7 +9,6 @@ import Logger from './Logger';
import debug from 'debug';
import RoomClient from './RoomClient';
import RoomContext from './RoomContext';
import * as cookiesManager from './cookiesManager';
import * as stateActions from './actions/stateActions';
import Room from './components/Room';
import LoadingView from './components/LoadingView';
@ -51,8 +50,6 @@ function run()
let roomId = (urlParser.pathname).substr(1)
? (urlParser.pathname).substr(1).toLowerCase() : urlParser.query.roomId.toLowerCase();
const produce = urlParser.query.produce !== 'false';
let displayName = urlParser.query.displayName;
const useSimulcast = urlParser.query.simulcast === 'true';
if (!roomId)
@ -82,24 +79,6 @@ function run()
const roomUrl = roomUrlParser.toString();
// Get displayName from cookie (if not already given as param).
const userCookie = cookiesManager.getUser() || {};
let displayNameSet;
if (!displayName)
displayName = userCookie.displayName;
if (displayName)
{
displayNameSet = true;
}
else
{
displayName = 'Guest';
displayNameSet = false;
}
// Get current device.
const device = getDeviceInfo();
@ -109,15 +88,13 @@ function run()
store.dispatch(
stateActions.setMe({
peerName,
displayName,
displayNameSet,
device,
loginEnabled : window.config.loginEnabled
})
);
roomClient = new RoomClient(
{ roomId, peerName, displayName, device, useSimulcast, produce });
{ roomId, peerName, device, useSimulcast, produce });
global.CLIENT = roomClient;

View File

@ -1,8 +1,6 @@
const initialState =
{
name : null,
displayName : null,
displayNameSet : false,
device : null,
canSendMic : false,
canSendWebcam : false,
@ -14,14 +12,8 @@ const initialState =
audioInProgress : false,
screenShareInProgress : false,
loginEnabled : false,
audioOnly : false,
audioOnlyInProgress : false,
raiseHand : false,
raiseHandInProgress : false,
restartIceInProgress : false,
picture : null,
selectedWebcam : null,
selectedAudioDevice : null,
loggedIn : false
};
@ -33,8 +25,6 @@ const me = (state = initialState, action) =>
{
const {
peerName,
displayName,
displayNameSet,
device,
loginEnabled
} = action.payload;
@ -42,8 +32,6 @@ const me = (state = initialState, action) =>
return {
...state,
name : peerName,
displayName,
displayNameSet,
device,
loginEnabled
};
@ -55,16 +43,6 @@ const me = (state = initialState, action) =>
case 'USER_LOGOUT':
return { ...state, loggedIn: false };
case 'CHANGE_WEBCAM':
{
return { ...state, selectedWebcam: action.payload.deviceId };
}
case 'CHANGE_AUDIO_DEVICE':
{
return { ...state, selectedAudioDevice: action.payload.deviceId };
}
case 'SET_MEDIA_CAPABILITIES':
{
const { canSendMic, canSendWebcam } = action.payload;
@ -114,31 +92,6 @@ const me = (state = initialState, action) =>
return { ...state, screenShareInProgress: flag };
}
case 'SET_DISPLAY_NAME':
{
let { displayName } = action.payload;
// Be ready for undefined displayName (so keep previous one).
if (!displayName)
displayName = state.displayName;
return { ...state, displayName, displayNameSet: true };
}
case 'SET_AUDIO_ONLY_STATE':
{
const { enabled } = action.payload;
return { ...state, audioOnly: enabled };
}
case 'SET_AUDIO_ONLY_IN_PROGRESS':
{
const { flag } = action.payload;
return { ...state, audioOnlyInProgress: flag };
}
case 'SET_MY_RAISE_HAND_STATE':
{
const { flag } = action.payload;
@ -153,18 +106,6 @@ const me = (state = initialState, action) =>
return { ...state, raiseHandInProgress: flag };
}
case 'SET_RESTART_ICE_IN_PROGRESS':
{
const { flag } = action.payload;
return { ...state, restartIceInProgress: flag };
}
case 'SET_PICTURE':
{
return { ...state, picture: action.payload.picture };
}
default:
return state;
}

View File

@ -8,7 +8,6 @@ const initialState =
activeSpeakerName : null,
torrentSupport : false,
showSettings : false,
advancedMode : false,
fullScreenConsumer : null, // ConsumerID
windowConsumer : null, // ConsumerID
toolbarsVisible : true,
@ -89,13 +88,6 @@ const room = (state = initialState, action) =>
return { ...state, showSettings };
}
case 'TOGGLE_ADVANCED_MODE':
{
const advancedMode = !state.advancedMode;
return { ...state, advancedMode };
}
case 'TOGGLE_FULLSCREEN_CONSUMER':
{
const { consumerId } = action.payload;

View File

@ -9,6 +9,7 @@ import notifications from './notifications';
import chatmessages from './chatmessages';
import toolarea from './toolarea';
import files from './files';
import settings from './settings';
export default combineReducers({
room,
@ -20,5 +21,6 @@ export default combineReducers({
notifications,
chatmessages,
toolarea,
files
files,
settings
});

View File

@ -0,0 +1,52 @@
const initialState =
{
displayName : 'Guest',
picture : null,
selectedWebcam : null,
selectedAudioDevice : null,
advancedMode : false
};
const settings = (state = initialState, action) =>
{
switch (action.type)
{
case 'CHANGE_WEBCAM':
{
return { ...state, selectedWebcam: action.payload.deviceId };
}
case 'CHANGE_AUDIO_DEVICE':
{
return { ...state, selectedAudioDevice: action.payload.deviceId };
}
case 'SET_DISPLAY_NAME':
{
let { displayName } = action.payload;
// Be ready for undefined displayName (so keep previous one).
if (!displayName)
displayName = state.displayName;
return { ...state, displayName };
}
case 'SET_PICTURE':
{
return { ...state, picture: action.payload.picture };
}
case 'TOGGLE_ADVANCED_MODE':
{
const advancedMode = !state.advancedMode;
return { ...state, advancedMode };
}
default:
return state;
}
};
export default settings;

View File

@ -15,7 +15,7 @@ const persistConfig =
key : 'root',
storage : storage,
stateReconciler : autoMergeLevel2,
whitelist : []
whitelist : [ 'settings' ]
};
const reduxMiddlewares =