TT#47718 Select participant in main content area

- selected ParticipantItem's video in fullscreen (#67702)
- placeholder icon for none existing video of the current selected participant (#67706)
- current selected ParticipantItem's name as title (#67703)
- local participant selected by default (#67704)

Change-Id: I6e2e47609adc407363be0c1636ff0ae8bd30ad38
changes/03/34803/11
Carlo Venusino 6 years ago
parent 81f46b5216
commit 8cf6234e63

@ -43,9 +43,37 @@
v-if="!isJoining && isJoined"
/>
</div>
<q-icon
name="person"
class="csc-conf-selected-avatar"
v-show="!isJoining
&& isJoined
&& selectedParticipant
&& !selectedHasVideo"
>
</q-icon>
<div
id="csc-conf-selected-participant-name"
v-show="!isJoining
&& isJoined
&& selectedParticipantName"
>
{{selectedParticipantName}}
</div>
<div
id="csc-conf-main-media"
v-show="isMediaEnabled && (isCameraEnabled || isScreenEnabled)"
v-show="!isJoined
&& isMediaEnabled
&& ( isCameraEnabled || isScreenEnabled )
|| (selectedParticipant
&& (selectedParticipant == 'local'
&& isMediaEnabled
&& (isCameraEnabled
|| isScreenEnabled)
)
|| selectedHasVideo
)"
>
<csc-media
ref="localMedia"
@ -100,6 +128,7 @@
<script>
import {
mapGetters,
mapState,
mapActions
} from 'vuex'
import CscConferenceJoin from '../pages/Conference/CscConferenceJoin'
@ -109,12 +138,18 @@
import CscSpinner from "../CscSpinner";
import {
QLayout,
QBtn
QBtn,
QCard,
QCardMedia,
QIcon
} from 'quasar-framework'
import CscConfirmDialog from "../CscConfirmationDialog";
export default {
data () {
return {}
data: function () {
return {
selectedMediaStream : null,
selectedParticipantName: null
}
},
mounted() {
this.$store.dispatch('user/initUser');
@ -127,9 +162,15 @@
CscConferenceJoined,
CscConferenceParticipants,
QLayout,
QBtn
QBtn,
QCard,
QCardMedia,
QIcon
},
computed: {
...mapState('conference',[
'selectedParticipant'
]),
...mapGetters('conference', [
'conferenceId',
'conferenceUrl',
@ -141,10 +182,13 @@
'isCameraEnabled',
'isScreenEnabled',
'isMediaEnabled',
'localParticipant',
'localMediaStream',
'participantsList',
'remoteParticipant',
'remoteMediaStream',
'remoteMediaStreams'
'remoteMediaStreams',
'hasRemoteVideo'
]),
microphoneButtonColor() {
if(this.isMicrophoneEnabled) {
@ -169,6 +213,17 @@
else {
return 'grey';
}
},
selectedHasVideo(){
const selectedParticipant = this.selectedParticipant;
switch(true){
case !selectedParticipant:
return false;
case selectedParticipant == 'local':
return this.isMediaEnabled && (this.isCameraEnabled || this.isScreenEnabled);
default:
return this.hasRemoteVideo(selectedParticipant);
}
}
},
methods: {
@ -204,6 +259,24 @@
if(this.hasConferenceId) {
await this.$store.dispatch('conference/join', conferenceId);
}
},
showSelectedParticipant: ( participant, scope )=>{
if(scope.$refs.localMedia) {
switch(participant){
case 'local':
if(scope.localParticipant){
scope.selectedParticipantName = scope.localParticipant.displayName
scope.selectedMediaStream = scope.localMediaStream
scope.$refs.localMedia.assignStream(scope.selectedMediaStream);
}
break;
default:
scope.selectedMediaStream = scope.remoteMediaStream(participant);
scope.$refs.localMedia.assignStream(scope.selectedMediaStream);
scope.selectedParticipantName = scope.remoteParticipant(participant).displayName
break;
}
}
}
},
watch: {
@ -212,6 +285,14 @@
this.$store.commit('conference/disposeLocalMedia');
}
},
selectedParticipant:{
handler: function(participant){
if(participant){
this.showSelectedParticipant(participant, this);
}
},
deep: true
},
localMediaStream(stream) {
if (this.$refs.localMedia && (stream === null || stream === undefined)) {
this.$refs.localMedia.reset();
@ -223,6 +304,19 @@
<style lang="stylus" rel="stylesheet/stylus">
@import '../../themes/app.common.styl'
#csc-conf-selected-participant-name
position absolute
top 20px
bottom 0
right 0
left 0
z-index 2
background-color $conf-participant-box-color
color $primary
font-size 20px
width 130px
height 45px
padding 10px
#csc-conf-main-media
position absolute
top 0

@ -2,14 +2,13 @@
<q-card
class="csc-conf-participant-cont"
>
<q-card-media
class="csc-avatar-cont"
<q-icon
name="person"
class="csc-conf-avatar"
v-if="!localMediaStream || localMediaStream && (!isCameraEnabled && !isScreenEnabled)"
>
<img
src="statics/avatar.png"
/>
</q-card-media>
</q-icon>
<csc-media
ref="cscMedia"
v-show="localMediaStream && (isCameraEnabled || isScreenEnabled)"
@ -26,11 +25,12 @@
</template>
<script>
import { QCard, QCardMedia, QCardTitle } from 'quasar-framework'
import { QIcon, QCard, QCardMedia, QCardTitle } from 'quasar-framework'
import CscMedia from "../../CscMedia";
export default {
name: 'csc-conference-local-participant',
components: {
QIcon,
QCard,
QCardMedia,
QCardTitle,

@ -5,6 +5,7 @@
>
<csc-conference-local-participant
ref="localParticipant"
@click.native="setSelectedParticipant('local')"
:local-participant="localParticipant"
:local-media-stream="localMediaStream"
:is-microphone-enabled="isMicrophoneEnabled"
@ -17,7 +18,7 @@
:key="participantId"
>
<csc-conference-remote-participant
:key="participantId"
@click.native="setSelectedParticipant(participantId)"
:remote-participant="remoteParticipant(participantId)"
:has-remote-video="hasRemoteVideo(participantId)"
:remote-media-stream="remoteMediaStream"
@ -60,7 +61,7 @@
'isScreenEnabled',
'remoteParticipant',
'remoteMediaStream',
'hasRemoteVideo'
'hasRemoteVideo',
])
},
mounted() {
@ -71,6 +72,9 @@
if(this.$refs.localParticipant) {
this.$refs.localParticipant.assignStream(stream);
}
},
setSelectedParticipant(participant){
this.$store.commit('conference/setSelectedParticipant', participant);
}
},
watch: {

@ -2,14 +2,12 @@
<q-card
class="csc-conf-participant-cont"
>
<q-card-media
class="csc-avatar-cont"
v-show="!hasRemoteVideo"
<q-icon
name="person"
class="csc-conf-avatar"
v-if="!hasRemoteVideo"
>
<img
src="statics/avatar.png"
/>
</q-card-media>
</q-icon>
<csc-media
v-show="hasRemoteVideo"
class="csc-media-cont"
@ -26,30 +24,48 @@
</template>
<script>
import {QCard, QCardMedia, QCardTitle} from 'quasar-framework'
import { QIcon, QCard, QCardMedia, QCardTitle } from 'quasar-framework'
import CscMedia from "../../CscMedia";
import {
mapGetters
} from 'vuex'
export default {
name: 'csc-conference-remote-participant',
components: {
QIcon,
QCard,
QCardMedia,
QCardTitle,
CscMedia
},
data: function () {
return {
localMediaStream : null
}
},
props: [
'remoteParticipant',
'remoteMediaStream',
'remoteMediaStreams',
'hasRemoteVideo',
],
computed: {
...mapGetters('conference', [
'selectedParticipant'
])
},
mounted() {
this.assignStream();
this.assignStream(this);
},
methods: {
assignStream() {
if (this.$refs.cscMedia && this.remoteMediaStreams[this.remoteParticipant.id] === this.remoteParticipant.id) {
this.$refs.cscMedia.assignStream(this.remoteMediaStream(this.remoteParticipant.id));
assignStream: (scope) => {
if (scope.$refs.cscMedia && scope.remoteMediaStreams[scope.remoteParticipant.id] === scope.remoteParticipant.id) {
scope.localMediaStream = scope.remoteMediaStream(scope.remoteParticipant.id);
scope.$refs.cscMedia.assignStream(scope.localMediaStream);
if(scope.selectedParticipant == scope.remoteParticipant.id){
scope.$store.commit('conference/setSelectedParticipant', 'local'); // TODO improve (workaround to reset the mediaStream)
scope.$store.commit('conference/setSelectedParticipant', scope.remoteParticipant.id);
}
}
else if (this.$refs.cscMedia) {
this.$refs.cscMedia.reset();
@ -58,7 +74,7 @@
},
watch: {
remoteMediaStreams() {
this.assignStream();
this.assignStream(this);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

@ -25,7 +25,8 @@ export default {
leaveState: RequestState.initiated,
leaveError: null,
participants: [],
remoteMediaStreams: {}
remoteMediaStreams: {},
selectedParticipant: null
},
getters: {
username(state, getters, rootState, rootGetters) {
@ -107,6 +108,9 @@ export default {
return participant.mediaStream ? participant.mediaStream.hasVideo() : false;
}
return false;
},
selectedParticipant(state){
return state.selectedParticipant;
}
},
mutations: {
@ -169,6 +173,7 @@ export default {
state.joinState = RequestState.succeeded;
state.joinError = null;
state.leaveState = null;
state.selectedParticipant = 'local'
},
joinFailed(state, error) {
state.joinState = RequestState.failed;
@ -184,6 +189,7 @@ export default {
state.leaveError = null;
state.joinState = RequestState.initiated;
state.joinError = null;
state.selectedParticipant = null;
},
leaveFailed(state, error) {
state.leaveState = RequestState.failed;
@ -199,10 +205,20 @@ export default {
},
participantLeft(state, participant) {
if(state.selectedParticipant == 'local' && !state.joinState === RequestState.succeeded){
state.selectedParticipant = null;
}
else if(state.selectedParticipant == participant.getId()){
state.selectedParticipant = 'local';
}
state.participants = state.participants.filter(($participant) => {
return participant.getId() !== $participant;
});
Vue.delete(state.remoteMediaStreams, participant.getId());
},
setSelectedParticipant(state, participant){
state.selectedParticipant = participant;
}
},
actions: {

@ -129,6 +129,7 @@ export const store = new Vuex.Store({
});
}).onConferenceParticipantLeft((participant)=>{
store.commit('conference/participantLeft', participant);
store.commit('conference/removeRemoteMedia', participant.id);
}).onConferenceEvent((event)=>{
store.commit('conference/event', event);
}).onConferenceMessage((message)=>{

@ -247,25 +247,50 @@ input.q-input-target
i
margin 0
.csc-conf-avatar
font-size 137px
color $conf-participant-icon-color
padding-left 11px
background-color transparent;
box-shadow none
position relative
width 100%
height 100%
top 0
bottom 0
left -22px
right 0
margin auto
.csc-conf-selected-avatar
width: 220px;
height: 220px;
font-size 220px
color $conf-participant-icon-color
background-color transparent;
box-shadow none
position absolute
top 0
bottom 0
left 0
right 0
margin auto
.csc-conf-participant-cont
margin-bottom 20px
width 115px
height 115px
background white
background $conf-participant-box-color
cursor pointer
.csc-conf-participants-item-title
position relative
background white
bottom 24px
text-align center
padding 0
background rgba(0, 0, 0, 0.5)
background $conf-participant-box-color
.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

@ -94,3 +94,6 @@ $popover-box-shadow = $shadow-1
$loading-background = $main-menu-background
$chip-color = $dark
$conf-participant-icon-color = rgba(255, 255, 255, 0.6);
$conf-participant-box-color = rgba(21,29,48,0.8);

Loading…
Cancel
Save