Implements "raised hand".

This commit is contained in:
Boris Grozev 2016-06-20 16:13:17 -05:00
parent 4b6ac38058
commit 2d2e27b8d0
8 changed files with 158 additions and 34 deletions

View File

@ -394,6 +394,14 @@ export default {
videoMuted: false,
isSharingScreen: false,
isDesktopSharingEnabled: false,
/*
* Whether the local "raisedHand" flag is on.
*/
isHandRaised: false,
/*
* Whether the local participant is the dominant speaker in the conference.
*/
isDominantSpeaker: false,
/**
* Open new connection and join to the conference.
* @param {object} options
@ -1018,6 +1026,16 @@ export default {
APP.UI.handleLastNEndpoints(ids, enteringIds);
});
room.on(ConferenceEvents.DOMINANT_SPEAKER_CHANGED, (id) => {
if (this.isLocalId(id)) {
this.isDominantSpeaker = true;
this.setRaisedHand(false);
} else {
this.isDominantSpeaker = false;
var participant = room.getParticipantById(id);
if (participant) {
APP.UI.setRaisedHandStatus(participant, false);
}
}
APP.UI.markDominantSpeaker(id);
});
@ -1040,6 +1058,13 @@ export default {
APP.UI.changeDisplayName(id, displayName);
});
room.on(ConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,
(participant, name, oldValue, newValue) => {
if (name === "raisedHand") {
APP.UI.setRaisedHandStatus(participant, newValue);
}
});
room.on(ConferenceEvents.RECORDER_STATE_CHANGED, (status, error) => {
console.log("Received recorder status change: ", status, error);
APP.UI.updateRecordingState(status);
@ -1432,5 +1457,30 @@ export default {
mediaDeviceHelper.setCurrentMediaDevices(devices);
APP.UI.onAvailableDevicesChanged(devices);
});
},
/**
* Toggles the local "raised hand" status, if the current state allows
* toggling.
*/
maybeToggleRaisedHand() {
// If we are the dominant speaker, we don't enable "raise hand".
if (this.isHandRaised || !this.isDominantSpeaker) {
this.setRaisedHand(!this.isHandRaised);
}
},
/**
* Sets the local "raised hand" status to a particular value.
*/
setRaisedHand(raisedHand) {
if (raisedHand !== this.isHandRaised)
{
this.isHandRaised = raisedHand;
// Advertise the updated status
room.setLocalParticipantProperty("raisedHand", raisedHand);
// Update the view
APP.UI.setLocalRaisedHandStatus(raisedHand);
}
}
};

View File

@ -310,7 +310,7 @@
z-index: 3;
}
.videocontainer>span.dominantspeakerindicator {
.videocontainer>span.indicator {
bottom: 0px;
left: 0px;
width: 25px;
@ -327,7 +327,7 @@
border: 0px;
}
#speakerindicatoricon {
#indicatoricon {
padding-top: 5px;
}

View File

@ -8,6 +8,7 @@
"participant": "Participant",
"me": "me",
"speaker": "Speaker",
"raisedHand": "Would like to speak",
"defaultNickname": "ex. Jane Pink",
"defaultLink": "e.g. __url__",
"calling": "Calling __name__ ...",
@ -154,7 +155,8 @@
"grantedTo": "Moderator rights granted to __to__!",
"grantedToUnknown": "Moderator rights granted to $t(somebody)!",
"muted": "You have started the conversation muted.",
"mutedTitle": "You're muted!"
"mutedTitle": "You're muted!",
"raisedHand": "Would like to speak."
},
"dialog": {
"kickMessage": "Ouch! You have been kicked out of the meet!",

View File

@ -255,7 +255,25 @@ UI.changeDisplayName = function (id, displayName) {
};
/**
* Intitialize conference UI.
* Sets the "raised hand" status for a participant.
*/
UI.setRaisedHandStatus = (participant, raisedHandStatus) => {
VideoLayout.setRaisedHandStatus(participant.getId(), raisedHandStatus);
if (raisedHandStatus) {
messageHandler.notify(participant.getDisplayName(), 'notify.somebody',
'connected', 'notify.raisedHand');
}
};
/**
* Sets the local "raised hand" status.
*/
UI.setLocalRaisedHandStatus = (raisedHandStatus) => {
VideoLayout.setRaisedHandStatus(APP.conference.localId, raisedHandStatus);
};
/**
* Initialize conference UI.
*/
UI.initConference = function () {
let id = APP.conference.localId;

View File

@ -215,16 +215,19 @@ var messageHandler = {
},
/**
* Displayes notification.
* @param displayName display name of the participant that is associated with the notification.
* @param displayNameKey the key from the language file for the display name.
* Displays a notification.
* @param displayName the display name of the participant that is
* associated with the notification.
* @param displayNameKey the key from the language file for the display
* name. Only used if displayName i not provided.
* @param cls css class for the notification
* @param messageKey the key from the language file for the text of the message.
* @param messageKey the key from the language file for the text of the
* message.
* @param messageArguments object with the arguments for the message.
* @param options object with language options.
*/
notify: function(displayName, displayNameKey,
cls, messageKey, messageArguments, options) {
notify: function(displayName, displayNameKey, cls, messageKey,
messageArguments, options) {
if(!notificationsEnabled)
return;

View File

@ -422,37 +422,69 @@ SmallVideo.prototype.avatarChanged = function (avatarUrl) {
};
/**
* Updates the Indicator for dominant speaker.
*
* @param isSpeaker indicates the current indicator state
* Shows or hides the dominant speaker indicator.
* @param show whether to show or hide.
*/
SmallVideo.prototype.updateDominantSpeakerIndicator = function (isSpeaker) {
SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
if (!this.container) {
console.warn( "Unable to set dominant speaker indicator - "
+ this.videoSpanId + " does not exist");
return;
}
var indicatorSpan
= $('#' + this.videoSpanId + '>span.dominantspeakerindicator');
var indicatorSpanId = "dominantspeakerindicator";
var indicatorSpan = this.getIndicatorSpan(indicatorSpanId);
// If we do not have an indicator for this video.
if (indicatorSpan.length <= 0) {
indicatorSpan = document.createElement('span');
indicatorSpan.innerHTML
= "<i id='indicatoricon' class='fa fa-bullhorn'></i>";
// adds a tooltip
UIUtil.setTooltip(indicatorSpan, "speaker", "left");
APP.translation.translateElement($(indicatorSpan));
indicatorSpan.innerHTML
= "<i id='speakerindicatoricon' class='fa fa-bullhorn'></i>";
indicatorSpan.className = 'dominantspeakerindicator';
$(indicatorSpan).css("visibility", show ? "visible" : "hidden");
};
$('#' + this.videoSpanId)[0].appendChild(indicatorSpan);
// adds a tooltip
UIUtil.setTooltip(indicatorSpan, "speaker", "left");
APP.translation.translateElement($(indicatorSpan));
/**
* Shows or hides the raised hand indicator.
* @param show whether to show or hide.
*/
SmallVideo.prototype.showRaisedHandIndicator = function (show) {
if (!this.container) {
console.warn( "Unable to raised hand indication - "
+ this.videoSpanId + " does not exist");
return;
}
$(indicatorSpan).css("visibility", isSpeaker ? "visible" : "hidden");
var indicatorSpanId = "raisehandindicator";
var indicatorSpan = this.getIndicatorSpan(indicatorSpanId);
indicatorSpan.style.background = "#D6D61E";
indicatorSpan.innerHTML
= "<i id='indicatoricon' class='fa fa-hand-paper-o'></i>";
// adds a tooltip
UIUtil.setTooltip(indicatorSpan, "raisedHand", "left");
APP.translation.translateElement($(indicatorSpan));
$(indicatorSpan).css("visibility", show ? "visible" : "hidden");
};
/**
* Gets (creating if necessary) the "indicator" span for this SmallVideo
identified by an ID.
*/
SmallVideo.prototype.getIndicatorSpan = function(id) {
var indicatorSpan;
var spans = $(`#${this.videoSpanId}>[id=${id}`);
if (spans.length <= 0) {
indicatorSpan = document.createElement('span');
indicatorSpan.id = id;
indicatorSpan.className = "indicator";
$('#' + this.videoSpanId)[0].appendChild(indicatorSpan);
} else {
indicatorSpan = spans[0];
}
return indicatorSpan;
};
export default SmallVideo;

View File

@ -562,6 +562,18 @@ var VideoLayout = {
}
},
/**
* Sets the "raised hand" status for a participant identified by 'id'.
*/
setRaisedHandStatus(id, raisedHandStatus) {
var video
= APP.conference.isLocalId(id)
? localVideoThumbnail : remoteVideos[id];
if (video) {
video.showRaisedHandIndicator(raisedHandStatus);
}
},
/**
* On dominant speaker changed event.
*/
@ -576,10 +588,10 @@ var VideoLayout = {
if (APP.conference.isLocalId(id)) {
if(oldSpeakerRemoteVideo)
{
oldSpeakerRemoteVideo.updateDominantSpeakerIndicator(false);
oldSpeakerRemoteVideo.showDominantSpeakerIndicator(false);
currentDominantSpeaker = null;
}
localVideoThumbnail.updateDominantSpeakerIndicator(true);
localVideoThumbnail.showDominantSpeakerIndicator(true);
return;
}
@ -589,12 +601,12 @@ var VideoLayout = {
}
// Update the current dominant speaker.
remoteVideo.updateDominantSpeakerIndicator(true);
localVideoThumbnail.updateDominantSpeakerIndicator(false);
remoteVideo.showDominantSpeakerIndicator(true);
localVideoThumbnail.showDominantSpeakerIndicator(false);
// let's remove the indications from the remote video if any
if (oldSpeakerRemoteVideo) {
oldSpeakerRemoteVideo.updateDominantSpeakerIndicator(false);
oldSpeakerRemoteVideo.showDominantSpeakerIndicator(false);
}
currentDominantSpeaker = id;

View File

@ -40,6 +40,13 @@ function initShortcutHandlers() {
APP.conference.toggleAudioMuted();
}
},
82: {
character: "R",
function: function() {
APP.conference.maybeToggleRaisedHand();
}
},
84: {
character: "T",
function: function() {