diff --git a/src/components/layouts/Conference.vue b/src/components/layouts/Conference.vue index 37db24bc..86bfb4f2 100644 --- a/src/components/layouts/Conference.vue +++ b/src/components/layouts/Conference.vue @@ -39,6 +39,9 @@ +
-
+ + + + + + + {{ localParticipant.displayName }} + + + + + + + diff --git a/src/components/pages/Conference/CscConferenceParticipants.vue b/src/components/pages/Conference/CscConferenceParticipants.vue new file mode 100644 index 00000000..355aaff5 --- /dev/null +++ b/src/components/pages/Conference/CscConferenceParticipants.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/components/pages/Conference/CscConferenceRemoteParticipant.vue b/src/components/pages/Conference/CscConferenceRemoteParticipant.vue new file mode 100644 index 00000000..e2799de3 --- /dev/null +++ b/src/components/pages/Conference/CscConferenceRemoteParticipant.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/plugins/conference.js b/src/plugins/conference.js index 2cf7f506..780c8164 100644 --- a/src/plugins/conference.js +++ b/src/plugins/conference.js @@ -47,6 +47,7 @@ export class ConferencePlugin { return new Promise((resolve, reject)=>{ options.localMediaStream = this.getLocalMediaStream(); this.getNetwork().joinConference(options).then((conference)=>{ + this.conference = conference; resolve(conference); }).catch((err)=>{ reject(err); @@ -146,12 +147,13 @@ export class ConferencePlugin { } getLocalParticipant() { - this.conference.getLocalParticipant(); + return this.conference.getLocalParticipant(); } getRemoteParticipant(id) { - this.conference.getRemoteParticipant(id); + return this.conference.getRemoteParticipant(id); } + } export default { diff --git a/src/statics/avatar.png b/src/statics/avatar.png new file mode 100644 index 00000000..a1a75249 Binary files /dev/null and b/src/statics/avatar.png differ diff --git a/src/store/conference.js b/src/store/conference.js index c6ce2768..f1ab4e18 100644 --- a/src/store/conference.js +++ b/src/store/conference.js @@ -25,7 +25,8 @@ export default { joinError: null, leaveState: RequestState.initiated, leaveError: null, - participants: [] + participants: [], + remoteMediaStreams: [] }, getters: { username(state, getters, rootState, rootGetters) { @@ -78,7 +79,33 @@ export default { hasLocalMediaStream(state) { return (state.localMediaState === RequestState.succeeded || state.localMediaState === RequestState.requesting) && Vue.$conference.hasLocalMediaStream(); + }, + localParticipant(state) { + if(state.joinState === RequestState.succeeded){ + return Vue.$conference.getLocalParticipant(); + } + }, + remoteParticipant: () => (participantId) => { + return Vue.$conference.getRemoteParticipant(participantId); + }, + remoteMediaStream: (state) => (participantId) => { + if(state.remoteMediaStreams.includes(participantId)){ + const participant = Vue.$conference.getRemoteParticipant(participantId); + return participant.mediaStream ? participant.mediaStream.getStream() : null; + } + return null; + + }, + participantsList(state) { + return state.participants; + }, + remoteMediaStreams(state) { + return state.remoteMediaStreams; + }, + hasRemoteMediaStream: (state) => (participantId) => { + return state.remoteMediaStreams.includes(participantId) } + }, mutations: { enableConferencing(state) { @@ -126,6 +153,20 @@ export default { state.microphoneEnabled = false; state.screenEnabled = false; }, + addRemoteMedia(state, participantId) { + if(state.remoteMediaStreams.includes(participantId)){ + state.remoteMediaStreams = state.remoteMediaStreams.filter(($participant)=>{ + return participantId !== $participant; + }); + } + state.remoteMediaStreams.push(participantId); + + }, + removeRemoteMedia(state, participant) { + state.remoteMediaStreams = state.remoteMediaStreams.filter(($participant)=>{ + return participant !== $participant; + }); + }, joinRequesting(state) { state.joinState = RequestState.requesting; state.joinError = null; @@ -133,6 +174,7 @@ export default { joinSucceeded(state) { state.joinState = RequestState.succeeded; state.joinError = null; + state.leaveState = null; }, joinFailed(state, error) { state.joinState = RequestState.failed; @@ -141,6 +183,7 @@ export default { leaveRequesting(state) { state.leaveState = RequestState.requesting; state.leaveError = null; + state.joinState = null; }, leaveSucceeded(state) { state.leaveState = RequestState.succeeded; @@ -153,12 +196,16 @@ export default { state.leaveError = error; }, participantJoined(state, participant) { - state.participants.push(participant.getId()); - + if(state.participants.includes(participant.getId())){ + state.participants = state.participants.filter(($participant)=>{ + return participant.getId() !== $participant; + }); + } + state.participants.push(participant.getId()) }, participantLeft(state, participant) { state.participants = state.participants.filter(($participant)=>{ - return participant.getId() !== $participant.getId(); + return participant.getId() !== $participant; }); } }, diff --git a/src/store/index.js b/src/store/index.js index d1cf3dbd..e17a247c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -121,6 +121,19 @@ export const store = new Vuex.Store({ store.commit('conference/leftSuccessfully', conference); }).onConferenceParticipantJoined((participant)=>{ store.commit('conference/participantJoined', participant); + participant.onMediaStream(()=>{ + store.commit('conference/addRemoteMedia', participant.id); + }) + participant.onMediaStarted(()=>{ + store.commit('conference/addRemoteMedia', participant.id); + }) + participant.onMediaRecovered(()=>{ + store.commit('conference/addRemoteMedia', participant.id); + }) + participant.onMediaEnded(()=>{ + store.commit('conference/removeRemoteMedia', participant.id); + }) + }).onConferenceParticipantLeft((participant)=>{ store.commit('conference/participantLeft', participant); }).onConferenceEvent((event)=>{ diff --git a/src/themes/app.common.styl b/src/themes/app.common.styl index bad4384e..4b6e057c 100644 --- a/src/themes/app.common.styl +++ b/src/themes/app.common.styl @@ -247,3 +247,27 @@ input.q-input-target i margin 0 +.csc-conf-participant-cont + margin-bottom 20px + width 115px + height 115px + background white + .csc-conf-participants-item-title + position relative + background white + bottom 24px + text-align center + padding 0 + background rgba(0, 0, 0, 0.5) + .q-card-title + color $primary + font-size 12px + line-height 24px + .csc-avatar-cont + height 100% + top 6px + .csc-media-cont + height 100% !important + width 100% !important + video + height: 100%;