-
![]()
+

+
{peer.displayName}
diff --git a/app/lib/redux/reducers/chatmessages.js b/app/lib/redux/reducers/chatmessages.js
index e95789e..020908e 100644
--- a/app/lib/redux/reducers/chatmessages.js
+++ b/app/lib/redux/reducers/chatmessages.js
@@ -3,9 +3,7 @@ import
createNewMessage
} from './helper';
-const initialState = [];
-
-const chatmessages = (state = initialState, action) =>
+const chatmessages = (state = [], action) =>
{
switch (action.type)
{
diff --git a/app/lib/redux/reducers/helper.js b/app/lib/redux/reducers/helper.js
index 1423eb1..db17859 100644
--- a/app/lib/redux/reducers/helper.js
+++ b/app/lib/redux/reducers/helper.js
@@ -1,10 +1,11 @@
-export function createNewMessage(text, sender, name)
+export function createNewMessage(text, sender, name, picture)
{
return {
type : 'message',
text,
time : Date.now(),
name,
- sender
+ sender,
+ picture
};
-}
+}
\ No newline at end of file
diff --git a/app/lib/redux/reducers/me.js b/app/lib/redux/reducers/me.js
index 75e89ae..0b8db12 100644
--- a/app/lib/redux/reducers/me.js
+++ b/app/lib/redux/reducers/me.js
@@ -21,7 +21,8 @@ const initialState =
audioOnlyInProgress : false,
raiseHand : false,
raiseHandInProgress : false,
- restartIceInProgress : false
+ restartIceInProgress : false,
+ picture : null
};
const me = (state = initialState, action) =>
@@ -164,6 +165,11 @@ const me = (state = initialState, action) =>
return { ...state, restartIceInProgress: flag };
}
+ case 'SET_PICTURE':
+ {
+ return { ...state, picture: action.payload.picture };
+ }
+
default:
return state;
}
diff --git a/app/lib/redux/reducers/peers.js b/app/lib/redux/reducers/peers.js
index d7174d5..ea9cb44 100644
--- a/app/lib/redux/reducers/peers.js
+++ b/app/lib/redux/reducers/peers.js
@@ -1,126 +1,93 @@
-const initialState = {};
+import omit from 'lodash/omit';
-const peers = (state = initialState, action) =>
+const peer = (state = {}, action) =>
+{
+ switch (action.type)
+ {
+ case 'ADD_PEER':
+ return action.payload.peer;
+
+ case 'SET_PEER_DISPLAY_NAME':
+ return { ...state, displayName: action.payload.displayName };
+
+ case 'SET_PEER_VIDEO_IN_PROGRESS':
+ return { ...state, peerVideoInProgress: action.payload.flag };
+
+ case 'SET_PEER_AUDIO_IN_PROGRESS':
+ return { ...state, peerAudioInProgress: action.payload.flag };
+
+ case 'SET_PEER_SCREEN_IN_PROGRESS':
+ return { ...state, peerScreenInProgress: action.payload.flag };
+
+ case 'SET_PEER_RAISE_HAND_STATE':
+ return { ...state, raiseHandState: action.payload.raiseHandState };
+
+ case 'ADD_CONSUMER':
+ {
+ const consumers = [ ...state.consumers, action.payload.consumer.id ];
+
+ return { ...state, consumers };
+ }
+
+ case 'REMOVE_CONSUMER':
+ {
+ const consumers = state.consumers.filter((consumer) =>
+ consumer !== action.payload.consumerId);
+
+ return { ...state, consumers };
+ }
+
+ case 'SET_PEER_PICTURE':
+ {
+ return { ...state, picture: action.payload.picture };
+ }
+
+ default:
+ return state;
+ }
+};
+
+const peers = (state = {}, action) =>
{
switch (action.type)
{
case 'ADD_PEER':
{
- const { peer } = action.payload;
-
- return { ...state, [peer.name]: peer };
+ return { ...state, [action.payload.peer.name]: peer(undefined, action) };
}
case 'REMOVE_PEER':
{
- const { peerName } = action.payload;
- const newState = { ...state };
-
- delete newState[peerName];
-
- return newState;
+ return omit(state, [ action.payload.peerName ]);
}
case 'SET_PEER_DISPLAY_NAME':
- {
- const { displayName, peerName } = action.payload;
- const peer = state[peerName];
-
- if (!peer)
- throw new Error('no Peer found');
-
- const newPeer = { ...peer, displayName };
-
- return { ...state, [newPeer.name]: newPeer };
- }
-
case 'SET_PEER_VIDEO_IN_PROGRESS':
- {
- const { peerName, flag } = action.payload;
- const peer = state[peerName];
-
- if (!peer)
- throw new Error('no Peer found');
-
- const newPeer = { ...peer, peerVideoInProgress: flag };
-
- return { ...state, [newPeer.name]: newPeer };
- }
-
case 'SET_PEER_AUDIO_IN_PROGRESS':
- {
- const { peerName, flag } = action.payload;
- const peer = state[peerName];
-
- if (!peer)
- throw new Error('no Peer found');
-
- const newPeer = { ...peer, peerAudioInProgress: flag };
-
- return { ...state, [newPeer.name]: newPeer };
- }
-
case 'SET_PEER_SCREEN_IN_PROGRESS':
- {
- const { peerName, flag } = action.payload;
- const peer = state[peerName];
-
- if (!peer)
- throw new Error('no Peer found');
-
- const newPeer = { ...peer, peerScreenInProgress: flag };
-
- return { ...state, [newPeer.name]: newPeer };
- }
-
case 'SET_PEER_RAISE_HAND_STATE':
- {
- const { peerName, raiseHandState } = action.payload;
- const peer = state[peerName];
-
- if (!peer)
- throw new Error('no Peer found');
-
- const newPeer = { ...peer, raiseHandState };
-
- return { ...state, [newPeer.name]: newPeer };
- }
-
+ case 'SET_PEER_PICTURE':
case 'ADD_CONSUMER':
{
- const { consumer, peerName } = action.payload;
- const peer = state[peerName];
+ const oldPeer = state[action.payload.peerName];
- if (!peer)
- throw new Error('no Peer found for new Consumer');
+ if (!oldPeer)
+ {
+ throw new Error('no Peer found');
+ }
- const newConsumers = [ ...peer.consumers, consumer.id ];
- const newPeer = { ...peer, consumers: newConsumers };
-
- return { ...state, [newPeer.name]: newPeer };
+ return { ...state, [oldPeer.name]: peer(oldPeer, action) };
}
-
+
case 'REMOVE_CONSUMER':
{
- const { consumerId, peerName } = action.payload;
- const peer = state[peerName];
+ const oldPeer = state[action.payload.peerName];
// NOTE: This means that the Peer was closed before, so it's ok.
- if (!peer)
+ if (!oldPeer)
return state;
- const idx = peer.consumers.indexOf(consumerId);
-
- if (idx === -1)
- throw new Error('Consumer not found');
-
- const newConsumers = peer.consumers.slice();
-
- newConsumers.splice(idx, 1);
-
- const newPeer = { ...peer, consumers: newConsumers };
-
- return { ...state, [newPeer.name]: newPeer };
+ return { ...state, [oldPeer.name]: peer(oldPeer, action) };
}
default:
diff --git a/app/lib/redux/requestActions.js b/app/lib/redux/requestActions.js
index 5d9a240..6d54490 100644
--- a/app/lib/redux/requestActions.js
+++ b/app/lib/redux/requestActions.js
@@ -184,9 +184,9 @@ export const installExtension = () =>
};
};
-export const sendChatMessage = (text, name) =>
+export const sendChatMessage = (text, name, picture) =>
{
- const message = createNewMessage(text, 'response', name);
+ const message = createNewMessage(text, 'response', name, picture);
return {
type : 'SEND_CHAT_MESSAGE',
diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js
index 62307a8..9dcbb41 100644
--- a/app/lib/redux/stateActions.js
+++ b/app/lib/redux/stateActions.js
@@ -434,3 +434,15 @@ export const dropMessages = () =>
type : 'DROP_MESSAGES'
};
};
+
+export const setPicture = (picture) =>
+ ({
+ type : 'SET_PICTURE',
+ payload : { picture }
+ });
+
+export const setPeerPicture = (peerName, picture) =>
+ ({
+ type : 'SET_PEER_PICTURE',
+ payload : { peerName, picture }
+ });
\ No newline at end of file
diff --git a/app/resources/images/avatar-empty.jpeg b/app/resources/images/avatar-empty.jpeg
new file mode 100644
index 0000000..56c4679
Binary files /dev/null and b/app/resources/images/avatar-empty.jpeg differ
diff --git a/app/stylus/components/Chat.styl b/app/stylus/components/Chat.styl
index e7adc4e..0541e70 100644
--- a/app/stylus/components/Chat.styl
+++ b/app/stylus/components/Chat.styl
@@ -73,38 +73,33 @@
word-wrap: break-word;
> .client {
- background-color: rgba(#000, 0.1);
- border-radius: 5px;
- padding: 6px;
- max-width: 215px;
- text-align: left;
margin-left: auto;
-
- > .message-text {
- font-size: 1.3vmin;
- }
-
- > .message-time {
- font-size: 1vmin;
- opacity:0.8;
- }
}
- > .response {
+ > .client, > .response {
background-color: rgba(#000, 0.1);
border-radius: 5px;
- padding: 6px;
max-width: 215px;
- text-align: left;
- font-size: 1.3vmin;
+ display: flex;
+ align-items: center;
+ padding: 6px;
- > .message-text {
- font-size: 1.3vmin;
+ > .message-avatar {
+ height: 2rem;
+ border-radius: 50%;
}
- > .message-time {
- font-size: 1vmin;
- opacity: 0.8;
+ > .message-content {
+ padding-left: 6px;
+
+ > .message-text {
+ font-size: 1.3vmin;
+ }
+
+ > .message-time {
+ font-size: 1vmin;
+ opacity: 0.8;
+ }
}
}
}
diff --git a/app/stylus/components/ParticipantList.styl b/app/stylus/components/ParticipantList.styl
index 9481fad..7f4328a 100644
--- a/app/stylus/components/ParticipantList.styl
+++ b/app/stylus/components/ParticipantList.styl
@@ -15,6 +15,8 @@
}
[data-component='ListPeer'] {
+ display: flex;
+
> .controls {
float: right;
display: flex;
@@ -110,22 +112,16 @@
}
> .avatar {
- padding: 8px 16px;
- float: left;
- width: auto;
- border: none;
- display: block;
- outline: 0;
- border-radius: 50%;
- vertical-align: middle;
+ border-radius: 50%;
+ height: 2rem;
}
> .peer-info {
- font-size: 1.4vmin;
- float: left;
- width: auto;
- border: none;
- outline: 0;
- padding: 1vmin;
+ font-size: 1.4vmin;
+ border: none;
+ display: flex;
+ padding: 1vmin;
+ flex-grow: 1;
+ align-items: center;
}
-}
+}
\ No newline at end of file
diff --git a/server/lib/Room.js b/server/lib/Room.js
index c6b5089..1f6d13c 100644
--- a/server/lib/Room.js
+++ b/server/lib/Room.js
@@ -228,6 +228,18 @@ class Room extends EventEmitter
break;
}
+ case 'change-profile-picture':
+ {
+ accept();
+
+ this._protooRoom.spread('profile-picture-changed', {
+ peerName: protooPeer.id,
+ picture: request.data.picture
+ }, [ protooPeer ]);
+
+ break;
+ }
+
case 'chat-message':
{
accept();