зеркало из https://github.com/nextcloud/spreed.git
Merge pull request #271 from nextcloud/select-screensharing
Select-Screensharing feature
This commit is contained in:
Коммит
7d70cd643e
|
@ -225,7 +225,7 @@ video {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.videoContainer.promoted .muteIndicator {
|
||||
.videoContainer.promoted .mediaIndicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
@ -268,10 +268,26 @@ video {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.participants-1 #toggleScreensharing {
|
||||
.participants-1 #screensharing-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#screensharing-menu {
|
||||
bottom: 44px;
|
||||
left: calc(50% - 40px);
|
||||
right: initial;
|
||||
color: initial;
|
||||
text-shadow: initial;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#screensharing-menu.app-navigation-entry-menu:after {
|
||||
top: 100%;
|
||||
left: calc(50% - 5px);
|
||||
border-top-color: #fff;
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
/* big speaker video */
|
||||
.participants-1 .videoContainer,
|
||||
.participants-2 .videoContainer,
|
||||
|
@ -399,22 +415,33 @@ video {
|
|||
opacity: .7;
|
||||
}
|
||||
|
||||
.muteIndicator {
|
||||
.mediaIndicator {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 44px;
|
||||
left: 0;
|
||||
background-size: 22px;
|
||||
padding: 12px;
|
||||
opacity: .7;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.muteIndicator.audio-on {
|
||||
.muteIndicator,
|
||||
.screensharingIndicator {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
background-color: transparent !important;
|
||||
border: none;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-size: 22px;
|
||||
}
|
||||
|
||||
.muteIndicator.audio-on,
|
||||
.screensharingIndicator.screen-off {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.muteIndicator.audio-off {
|
||||
display: block;
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
#app-content:-webkit-full-screen {
|
||||
|
|
24
js/app.js
24
js/app.js
|
@ -220,16 +220,17 @@
|
|||
|
||||
var screensharingStopped = function() {
|
||||
console.log("Screensharing now stopped");
|
||||
$('#toggleScreensharing').attr('data-original-title', 'Enable screensharing')
|
||||
$('#screensharing-button').attr('data-original-title', 'Enable screensharing')
|
||||
.addClass('screensharing-disabled icon-screen-off-white')
|
||||
.removeClass('icon-screen-white');
|
||||
$('#screensharing-menu').toggleClass('open', false);
|
||||
};
|
||||
|
||||
OCA.SpreedMe.webrtc.on('localScreenStopped', function() {
|
||||
screensharingStopped();
|
||||
});
|
||||
|
||||
$('#toggleScreensharing').click(function() {
|
||||
$('#screensharing-button').click(function() {
|
||||
var webrtc = OCA.SpreedMe.webrtc;
|
||||
if (!webrtc.capabilities.supportScreenSharing) {
|
||||
OC.Notification.showTemporary(t('spreed', 'Screensharing is not supported by your browser.'));
|
||||
|
@ -237,13 +238,11 @@
|
|||
}
|
||||
|
||||
if (webrtc.getLocalScreen()) {
|
||||
webrtc.stopScreenShare();
|
||||
screensharingStopped();
|
||||
$('#screensharing-menu').toggleClass('open');
|
||||
} else {
|
||||
webrtc.shareScreen(function(err) {
|
||||
if (!err) {
|
||||
OC.Notification.showTemporary(t('spreed', 'Screensharing is about to start…'));
|
||||
$('#toggleScreensharing').attr('data-original-title', 'Stop screensharing')
|
||||
$('#screensharing-button').attr('data-original-title', 'Screensharing options')
|
||||
.removeClass('screensharing-disabled icon-screen-off-white')
|
||||
.addClass('icon-screen-white');
|
||||
return;
|
||||
|
@ -256,7 +255,6 @@
|
|||
case "PERMISSION_DENIED":
|
||||
case "NotAllowedError":
|
||||
case "CEF_GETSCREENMEDIA_CANCELED": // Experimental, may go away in the future.
|
||||
OC.Notification.showTemporary(t('spreed', 'The screensharing request has been cancelled.'));
|
||||
break;
|
||||
case "EXTENSION_UNAVAILABLE":
|
||||
var extensionURL = null;
|
||||
|
@ -284,6 +282,18 @@
|
|||
}
|
||||
});
|
||||
|
||||
$("#show-screen-button").on('click', function() {
|
||||
var currentUser = OCA.SpreedMe.webrtc.connection.getSessionid();
|
||||
OCA.SpreedMe.sharedScreens.switchScreenToId(currentUser);
|
||||
|
||||
$('#screensharing-menu').toggleClass('open', false);
|
||||
});
|
||||
|
||||
$("#stop-screen-button").on('click', function() {
|
||||
OCA.SpreedMe.webrtc.stopScreenShare();
|
||||
screensharingStopped();
|
||||
});
|
||||
|
||||
$("#guestName").on('click', function() {
|
||||
$('#guestName').addClass('hidden');
|
||||
$("#guestNameInput").removeClass('hidden');
|
||||
|
|
164
js/webrtc.js
164
js/webrtc.js
|
@ -152,7 +152,9 @@ var spreedMappingTable = [];
|
|||
OCA.SpreedMe.webrtc = webrtc;
|
||||
|
||||
var spreedListofSpeakers = {};
|
||||
var spreedListofSharedScreens = {};
|
||||
var latestSpeakerId = null;
|
||||
var latestScreenId = null;
|
||||
var screenSharingActive = false;
|
||||
|
||||
window.addEventListener('resize', function() {
|
||||
|
@ -234,7 +236,7 @@ var spreedMappingTable = [];
|
|||
$('<div>')
|
||||
.addClass('videoContainer videoContainer-dummy')
|
||||
.append(newContainer.find('.nameIndicator').clone())
|
||||
.append(newContainer.find('.muteIndicator').clone())
|
||||
.append(newContainer.find('.mediaIndicator').clone())
|
||||
.append(newContainer.find('.speakingIndicator').clone())
|
||||
);
|
||||
|
||||
|
@ -310,6 +312,106 @@ var spreedMappingTable = [];
|
|||
}
|
||||
};
|
||||
|
||||
OCA.SpreedMe.sharedScreens = {
|
||||
getContainerId: function(id) {
|
||||
var currentUser = OCA.SpreedMe.webrtc.connection.getSessionid();
|
||||
if (currentUser === id) {
|
||||
return '#localScreenContainer';
|
||||
} else {
|
||||
var sanitizedId = id.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&");
|
||||
return '#container_' + sanitizedId + '_screen_incoming';
|
||||
}
|
||||
},
|
||||
switchScreenToId: function(id) {
|
||||
var selectedScreen = $(OCA.SpreedMe.sharedScreens.getContainerId(id));
|
||||
if(selectedScreen.find('video').length === 0) {
|
||||
console.warn('promote: no screen video found for ID', id);
|
||||
return;
|
||||
}
|
||||
|
||||
if(latestScreenId === id) {
|
||||
console.log('promote: no need to repromote same screen');
|
||||
return;
|
||||
}
|
||||
|
||||
var screenContainerId = null;
|
||||
for (var currentId in spreedListofSharedScreens) {
|
||||
// skip loop if the property is from prototype
|
||||
if (!spreedListofSharedScreens.hasOwnProperty(currentId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip non-string ids
|
||||
if (!(typeof currentId === 'string' || currentId instanceof String)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
screenContainerId = OCA.SpreedMe.sharedScreens.getContainerId(currentId);
|
||||
if (currentId === id) {
|
||||
$(screenContainerId).removeClass('hidden');
|
||||
} else {
|
||||
$(screenContainerId).addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Add screen visible icon to video container
|
||||
$('#videos').find('.screensharingIndicator').removeClass('screen-visible');
|
||||
$(OCA.SpreedMe.speakers.getContainerId(id)).find('.screensharingIndicator').addClass('screen-visible');
|
||||
|
||||
latestScreenId = id;
|
||||
},
|
||||
add: function(id) {
|
||||
if (!(typeof id === 'string' || id instanceof String)) {
|
||||
return;
|
||||
}
|
||||
|
||||
spreedListofSharedScreens[id] = (new Date()).getTime();
|
||||
|
||||
var screensharingIndicator = $(OCA.SpreedMe.speakers.getContainerId(id)).find('.screensharingIndicator');
|
||||
screensharingIndicator.removeClass('screen-off');
|
||||
screensharingIndicator.addClass('screen-on');
|
||||
|
||||
OCA.SpreedMe.sharedScreens.switchScreenToId(id);
|
||||
},
|
||||
remove: function(id) {
|
||||
if (!(typeof id === 'string' || id instanceof String)) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete spreedListofSharedScreens[id];
|
||||
|
||||
var screensharingIndicator = $(OCA.SpreedMe.speakers.getContainerId(id)).find('.screensharingIndicator');
|
||||
screensharingIndicator.addClass('screen-off');
|
||||
screensharingIndicator.removeClass('screen-on');
|
||||
|
||||
var mostRecentTime = 0,
|
||||
mostRecentId = null;
|
||||
for (var currentId in spreedListofSharedScreens) {
|
||||
// skip loop if the property is from prototype
|
||||
if (!spreedListofSharedScreens.hasOwnProperty(currentId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip non-string ids
|
||||
if (!(typeof currentId === 'string' || currentId instanceof String)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var currentTime = spreedListofSharedScreens[currentId];
|
||||
if (currentTime > mostRecentTime) {
|
||||
mostRecentTime = currentTime;
|
||||
mostRecentId = currentId;
|
||||
}
|
||||
}
|
||||
|
||||
if (mostRecentId !== null) {
|
||||
OCA.SpreedMe.sharedScreens.switchScreenToId(mostRecentId);
|
||||
} else {
|
||||
console.log('No screens to promote');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OCA.SpreedMe.webrtc.on('createdPeer', function (peer) {
|
||||
peer.pc.on('PeerConnectionTrace', function (event) {
|
||||
console.log('trace', event);
|
||||
|
@ -415,10 +517,37 @@ var spreedMappingTable = [];
|
|||
avatarContainer.className = 'avatar-container hidden';
|
||||
avatarContainer.appendChild(avatar);
|
||||
|
||||
// Mute indicator
|
||||
var muteIndicator = document.createElement('div');
|
||||
muteIndicator.className = 'muteIndicator icon-audio-off-white audio-on';
|
||||
muteIndicator.textContent = '';
|
||||
// Media indicators
|
||||
var mediaIndicator = document.createElement('div');
|
||||
mediaIndicator.className = 'mediaIndicator';
|
||||
|
||||
var muteIndicator = document.createElement('button');
|
||||
muteIndicator.className = 'muteIndicator icon-audio-off-white audio-off';
|
||||
muteIndicator.disabled = true;
|
||||
|
||||
var screenSharingIndicator = document.createElement('button');
|
||||
screenSharingIndicator.className = 'screensharingIndicator icon-screen-white screen-off';
|
||||
screenSharingIndicator.setAttribute('data-original-title', 'Show screen');
|
||||
|
||||
screenSharingIndicator.onclick = function() {
|
||||
if (!this.classList.contains('screen-visible')) {
|
||||
OCA.SpreedMe.sharedScreens.switchScreenToId(peer.id);
|
||||
}
|
||||
$(this).tooltip('hide');
|
||||
};
|
||||
|
||||
$(screenSharingIndicator).tooltip({
|
||||
placement: 'top',
|
||||
trigger: 'hover'
|
||||
});
|
||||
|
||||
// Check if there is a screen from that user already added.
|
||||
if (spreedListofSharedScreens.hasOwnProperty(peer.id)) {
|
||||
$(screenSharingIndicator).removeClass('screen-off').addClass('screen-on');
|
||||
}
|
||||
|
||||
mediaIndicator.appendChild(muteIndicator);
|
||||
mediaIndicator.appendChild(screenSharingIndicator);
|
||||
|
||||
// Generic container
|
||||
var container = document.createElement('div');
|
||||
|
@ -427,7 +556,7 @@ var spreedMappingTable = [];
|
|||
container.appendChild(video);
|
||||
container.appendChild(avatarContainer);
|
||||
container.appendChild(userIndicator);
|
||||
container.appendChild(muteIndicator);
|
||||
container.appendChild(mediaIndicator);
|
||||
video.oncontextmenu = function() {
|
||||
return false;
|
||||
};
|
||||
|
@ -514,11 +643,12 @@ var spreedMappingTable = [];
|
|||
|
||||
// a peer was removed
|
||||
OCA.SpreedMe.webrtc.on('videoRemoved', function(video, peer) {
|
||||
|
||||
if (peer) {
|
||||
if (peer.type === 'video') {
|
||||
// a removed peer can't speak anymore ;)
|
||||
OCA.SpreedMe.speakers.remove(peer, true);
|
||||
} else if (peer.type === 'screen') {
|
||||
OCA.SpreedMe.sharedScreens.remove(peer.id);
|
||||
}
|
||||
|
||||
var remotes = document.getElementById(peer.type === 'screen' ? 'screens' : 'videos');
|
||||
|
@ -537,6 +667,8 @@ var spreedMappingTable = [];
|
|||
if (screens && localScreenContainer) {
|
||||
screens.removeChild(localScreenContainer);
|
||||
}
|
||||
|
||||
OCA.SpreedMe.sharedScreens.remove(OCA.SpreedMe.webrtc.connection.getSessionid());
|
||||
}
|
||||
|
||||
// Check if there are still some screens
|
||||
|
@ -573,12 +705,12 @@ var spreedMappingTable = [];
|
|||
userIndicator.className = 'nameIndicator';
|
||||
if (peer) {
|
||||
if (peer.nick) {
|
||||
userIndicator.textContent = peer.nick;
|
||||
userIndicator.textContent = t('spreed', "{participantName}'s screen", {participantName: peer.nick});
|
||||
} else {
|
||||
userIndicator.textContent = t('spreed', 'Guest');
|
||||
userIndicator.textContent = t('spreed', "Guest's screen");
|
||||
}
|
||||
} else {
|
||||
userIndicator.textContent = t('spreed', 'My screen');
|
||||
userIndicator.textContent = t('spreed', 'Your screen');
|
||||
}
|
||||
|
||||
// Generic container
|
||||
|
@ -591,6 +723,14 @@ var spreedMappingTable = [];
|
|||
return false;
|
||||
};
|
||||
|
||||
$(container).prependTo($('#screens'));
|
||||
|
||||
if (peer) {
|
||||
OCA.SpreedMe.sharedScreens.add(peer.id);
|
||||
} else {
|
||||
OCA.SpreedMe.sharedScreens.add(OCA.SpreedMe.webrtc.connection.getSessionid());
|
||||
}
|
||||
|
||||
// show the ice connection state
|
||||
if (peer && peer.pc) {
|
||||
peer.pc.on('iceConnectionStateChange', function () {
|
||||
|
@ -631,8 +771,6 @@ var spreedMappingTable = [];
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(container).prependTo($('#screens'));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -662,7 +800,7 @@ var spreedMappingTable = [];
|
|||
var screenNameIndicator = $(screen).find('.nameIndicator');
|
||||
|
||||
videoNameIndicator.text(data.name);
|
||||
screenNameIndicator.text(data.name);
|
||||
screenNameIndicator.text(t('spreed', "{participantName}'s screen", {participantName: data.name}));
|
||||
|
||||
if (latestSpeakerId === data.id) {
|
||||
OCA.SpreedMe.speakers.updateVideoContainerDummy(data.id);
|
||||
|
|
|
@ -67,7 +67,23 @@ script(
|
|||
<div class="nameIndicator">
|
||||
<button id="mute" class="icon-audio-white" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Mute audio')) ?>"></button>
|
||||
<button id="hideVideo" class="icon-video-white" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Disable video')) ?>"></button>
|
||||
<button id="toggleScreensharing" class="icon-screen-off-white screensharing-disabled" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Share screen')) ?>"></button>
|
||||
<button id="screensharing-button" class="app-navigation-entry-utils-menu-button icon-screen-off-white screensharing-disabled" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Share screen')) ?>"></button>
|
||||
<div id="screensharing-menu" class="app-navigation-entry-menu">
|
||||
<ul>
|
||||
<li>
|
||||
<button id="show-screen-button">
|
||||
<span class="icon-screen"></span>
|
||||
<span><?php p($l->t('Show your screen'));?></span>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button id="stop-screen-button">
|
||||
<span class="icon-screen-off"></span>
|
||||
<span><?php p($l->t('Stop screensharing'));?></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -50,7 +50,23 @@ script(
|
|||
<div class="nameIndicator">
|
||||
<button id="mute" class="icon-audio-white" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Mute audio')) ?>"></button>
|
||||
<button id="hideVideo" class="icon-video-white" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Disable video')) ?>"></button>
|
||||
<button id="toggleScreensharing" class="icon-screen-off-white screensharing-disabled" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Share screen')) ?>"></button>
|
||||
<button id="screensharing-button" class="app-navigation-entry-utils-menu-button icon-screen-off-white screensharing-disabled" data-placement="top" data-toggle="tooltip" data-original-title="<?php p($l->t('Share screen')) ?>"></button>
|
||||
<div id="screensharing-menu" class="app-navigation-entry-menu">
|
||||
<ul>
|
||||
<li>
|
||||
<button id="show-screen-button">
|
||||
<span class="icon-screen"></span>
|
||||
<span><?php p($l->t('Show your screen'));?></span>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button id="stop-screen-button">
|
||||
<span class="icon-screen-off"></span>
|
||||
<span><?php p($l->t('Stop screensharing'));?></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Загрузка…
Ссылка в новой задаче