ref(video-layout): get pinned ID directly from redux
This commit is contained in:
parent
57f7abc6dd
commit
05801711a7
|
@ -1,3 +1,5 @@
|
||||||
|
/* global APP */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright @ 2015 Atlassian Pty Ltd
|
* Copyright @ 2015 Atlassian Pty Ltd
|
||||||
*
|
*
|
||||||
|
@ -15,6 +17,10 @@
|
||||||
*/
|
*/
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
|
import {
|
||||||
|
getPinnedParticipant,
|
||||||
|
pinParticipant
|
||||||
|
} from '../react/features/base/participants';
|
||||||
import UIEvents from '../service/UI/UIEvents';
|
import UIEvents from '../service/UI/UIEvents';
|
||||||
import VideoLayout from './UI/videolayout/VideoLayout';
|
import VideoLayout from './UI/videolayout/VideoLayout';
|
||||||
|
|
||||||
|
@ -444,11 +450,15 @@ class FollowMe {
|
||||||
if (smallVideo) {
|
if (smallVideo) {
|
||||||
this.nextOnStageTimer = 0;
|
this.nextOnStageTimer = 0;
|
||||||
clearTimeout(this.nextOnStageTimout);
|
clearTimeout(this.nextOnStageTimout);
|
||||||
/* eslint-disable no-mixed-operators */
|
|
||||||
if (pin && !VideoLayout.isPinned(clickId)
|
if (pin) {
|
||||||
|| !pin && VideoLayout.isPinned(clickId)) {
|
APP.store.dispatch(pinParticipant(clickId));
|
||||||
/* eslint-disable no-mixed-operators */
|
} else {
|
||||||
VideoLayout.handleVideoThumbClicked(clickId);
|
const { id } = getPinnedParticipant(APP.store.getState()) || {};
|
||||||
|
|
||||||
|
if (id === clickId) {
|
||||||
|
APP.store.dispatch(pinParticipant(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If there's no SmallVideo object for the given id, lets wait and
|
// If there's no SmallVideo object for the given id, lets wait and
|
||||||
|
|
|
@ -959,15 +959,6 @@ UI.getLargeVideo = function() {
|
||||||
return VideoLayout.getLargeVideo();
|
return VideoLayout.getLargeVideo();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not the passed in user id is currently pinned to the large
|
|
||||||
* video.
|
|
||||||
*
|
|
||||||
* @param {string} userId - The id of the user to check is pinned or not.
|
|
||||||
* @returns {boolean} True if the user is currently pinned to the large video.
|
|
||||||
*/
|
|
||||||
UI.isPinned = userId => VideoLayout.getPinnedId() === userId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows "Please go to chrome webstore to install the desktop sharing extension"
|
* Shows "Please go to chrome webstore to install the desktop sharing extension"
|
||||||
* 2 button dialog with buttons - cancel and go to web store.
|
* 2 button dialog with buttons - cancel and go to web store.
|
||||||
|
|
|
@ -317,7 +317,7 @@ export default class SharedVideoManager {
|
||||||
name: 'YouTube'
|
name: 'YouTube'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
VideoLayout.handleVideoThumbClicked(self.url);
|
thumb.videoClick();
|
||||||
|
|
||||||
// If we are sending the command and we are starting the player
|
// If we are sending the command and we are starting the player
|
||||||
// we need to continuously send the player current time position
|
// we need to continuously send the player current time position
|
||||||
|
|
|
@ -59,7 +59,7 @@ SharedVideoThumb.prototype.createContainer = function(spanId) {
|
||||||
* The thumb click handler.
|
* The thumb click handler.
|
||||||
*/
|
*/
|
||||||
SharedVideoThumb.prototype.videoClick = function() {
|
SharedVideoThumb.prototype.videoClick = function() {
|
||||||
this.VideoLayout.handleVideoThumbClicked(this.url);
|
this._togglePin();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -260,7 +260,7 @@ LocalVideo.prototype._onContainerClick = function(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreClick) {
|
if (!ignoreClick) {
|
||||||
this.VideoLayout.handleVideoThumbClicked(this.id);
|
this._togglePin();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,10 @@ import { i18next } from '../../../react/features/base/i18n';
|
||||||
import {
|
import {
|
||||||
JitsiParticipantConnectionStatus
|
JitsiParticipantConnectionStatus
|
||||||
} from '../../../react/features/base/lib-jitsi-meet';
|
} from '../../../react/features/base/lib-jitsi-meet';
|
||||||
|
import {
|
||||||
|
getPinnedParticipant,
|
||||||
|
pinParticipant
|
||||||
|
} from '../../../react/features/base/participants';
|
||||||
import { PresenceLabel } from '../../../react/features/presence-status';
|
import { PresenceLabel } from '../../../react/features/presence-status';
|
||||||
import {
|
import {
|
||||||
REMOTE_CONTROL_MENU_STATES,
|
REMOTE_CONTROL_MENU_STATES,
|
||||||
|
@ -234,10 +237,12 @@ RemoteVideo.prototype._requestRemoteControlPermissions = function() {
|
||||||
if (result === true) {
|
if (result === true) {
|
||||||
// the remote control permissions has been granted
|
// the remote control permissions has been granted
|
||||||
// pin the controlled participant
|
// pin the controlled participant
|
||||||
const pinnedId = this.VideoLayout.getPinnedId();
|
const pinnedParticipant
|
||||||
|
= getPinnedParticipant(APP.store.getState()) || {};
|
||||||
|
const pinnedId = pinnedParticipant.id;
|
||||||
|
|
||||||
if (pinnedId !== this.id) {
|
if (pinnedId !== this.id) {
|
||||||
this.VideoLayout.handleVideoThumbClicked(this.id);
|
APP.store.dispatch(pinParticipant(this.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, error => {
|
}, error => {
|
||||||
|
@ -648,7 +653,7 @@ RemoteVideo.prototype._onContainerClick = function(event) {
|
||||||
|| classList.contains('popover');
|
|| classList.contains('popover');
|
||||||
|
|
||||||
if (!ignoreClick) {
|
if (!ignoreClick) {
|
||||||
this.VideoLayout.handleVideoThumbClicked(this.id);
|
this._togglePin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// On IE we need to populate this handler on video <object> and it does not
|
// On IE we need to populate this handler on video <object> and it does not
|
||||||
|
|
|
@ -12,7 +12,9 @@ import { AudioLevelIndicator }
|
||||||
from '../../../react/features/audio-level-indicator';
|
from '../../../react/features/audio-level-indicator';
|
||||||
import {
|
import {
|
||||||
Avatar as AvatarDisplay,
|
Avatar as AvatarDisplay,
|
||||||
getAvatarURLByParticipantId
|
getAvatarURLByParticipantId,
|
||||||
|
getPinnedParticipant,
|
||||||
|
pinParticipant
|
||||||
} from '../../../react/features/base/participants';
|
} from '../../../react/features/base/participants';
|
||||||
import {
|
import {
|
||||||
ConnectionIndicator
|
ConnectionIndicator
|
||||||
|
@ -819,6 +821,22 @@ SmallVideo.prototype.updateIndicators = function() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pins the participant displayed by this thumbnail or unpins if already pinned.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
SmallVideo.prototype._togglePin = function() {
|
||||||
|
const pinnedParticipant
|
||||||
|
= getPinnedParticipant(APP.store.getState()) || {};
|
||||||
|
const participantIdToPin
|
||||||
|
= pinnedParticipant && pinnedParticipant.id === this.id
|
||||||
|
? null : this.id;
|
||||||
|
|
||||||
|
APP.store.dispatch(pinParticipant(participantIdToPin));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the React element responsible for showing connection status, dominant
|
* Removes the React element responsible for showing connection status, dominant
|
||||||
* speaker, and raised hand icons.
|
* speaker, and raised hand icons.
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
JitsiParticipantConnectionStatus
|
JitsiParticipantConnectionStatus
|
||||||
} from '../../../react/features/base/lib-jitsi-meet';
|
} from '../../../react/features/base/lib-jitsi-meet';
|
||||||
import {
|
import {
|
||||||
getParticipants,
|
|
||||||
getPinnedParticipant,
|
getPinnedParticipant,
|
||||||
pinParticipant
|
pinParticipant
|
||||||
} from '../../../react/features/base/participants';
|
} from '../../../react/features/base/participants';
|
||||||
|
@ -42,6 +41,29 @@ function onLocalFlipXChanged(val) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the redux representation of all known users.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
function getAllParticipants() {
|
||||||
|
return APP.store.getState()['features/base/participants'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all thumbnails in the filmstrip.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
function getAllThumbnails() {
|
||||||
|
return [
|
||||||
|
localVideoThumbnail,
|
||||||
|
...Object.values(remoteVideos)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the user ID of the remote participant that is current the dominant
|
* Returns the user ID of the remote participant that is current the dominant
|
||||||
* speaker.
|
* speaker.
|
||||||
|
@ -50,7 +72,7 @@ function onLocalFlipXChanged(val) {
|
||||||
* @returns {string|null}
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
function getCurrentRemoteDominantSpeakerID() {
|
function getCurrentRemoteDominantSpeakerID() {
|
||||||
const dominantSpeaker = getParticipants(APP.store.getState)
|
const dominantSpeaker = getAllParticipants()
|
||||||
.find(participant => participant.dominantSpeaker);
|
.find(participant => participant.dominantSpeaker);
|
||||||
|
|
||||||
if (dominantSpeaker) {
|
if (dominantSpeaker) {
|
||||||
|
@ -93,8 +115,6 @@ const VideoLayout = {
|
||||||
// the local video thumb maybe one pixel
|
// the local video thumb maybe one pixel
|
||||||
this.resizeThumbnails(true);
|
this.resizeThumbnails(true);
|
||||||
|
|
||||||
this.handleVideoThumbClicked = this.handleVideoThumbClicked.bind(this);
|
|
||||||
|
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -376,61 +396,36 @@ const VideoLayout = {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the desired pinned participant and notifies web UI of the change.
|
* Callback invoked to update display when the pin participant has changed.
|
||||||
*
|
*
|
||||||
* @param {string|null} id - The participant id of the participant to be
|
* @paramn {string|null} pinnedParticipantID - The participant ID of the
|
||||||
* pinned. Pass in null to unpin without pinning another participant.
|
* participant that is pinned or null if no one is pinned.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
pinParticipant(id) {
|
onPinChange(pinnedParticipantID) {
|
||||||
APP.store.dispatch(pinParticipant(id));
|
if (interfaceConfig.filmStripOnly) {
|
||||||
APP.UI.emitEvent(UIEvents.PINNED_ENDPOINT, id, Boolean(id));
|
return;
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the click on a video thumbnail.
|
|
||||||
*
|
|
||||||
* @param id the identifier of the video thumbnail
|
|
||||||
*/
|
|
||||||
handleVideoThumbClicked(id) {
|
|
||||||
const smallVideo = VideoLayout.getSmallVideo(id);
|
|
||||||
const pinnedId = this.getPinnedId();
|
|
||||||
|
|
||||||
if (pinnedId) {
|
|
||||||
const oldSmallVideo = VideoLayout.getSmallVideo(pinnedId);
|
|
||||||
|
|
||||||
if (oldSmallVideo && !interfaceConfig.filmStripOnly) {
|
|
||||||
oldSmallVideo.focus(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpin if currently pinned.
|
getAllThumbnails().forEach(thumbnail =>
|
||||||
if (pinnedId === id) {
|
thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
|
||||||
this.pinParticipant(null);
|
|
||||||
|
|
||||||
// Enable the currently set dominant speaker.
|
if (pinnedParticipantID) {
|
||||||
if (getCurrentRemoteDominantSpeakerID()) {
|
this.updateLargeVideo(pinnedParticipantID);
|
||||||
this.updateLargeVideo(getCurrentRemoteDominantSpeakerID());
|
|
||||||
} else {
|
} else {
|
||||||
// if there is no currentDominantSpeaker, it can also be
|
const currentDominantSpeakerID
|
||||||
|
= getCurrentRemoteDominantSpeakerID();
|
||||||
|
|
||||||
|
if (currentDominantSpeakerID) {
|
||||||
|
this.updateLargeVideo(currentDominantSpeakerID);
|
||||||
|
} else {
|
||||||
|
// if there is no currentDominantSpeakerID, it can also be
|
||||||
// that local participant is the dominant speaker
|
// that local participant is the dominant speaker
|
||||||
// we should act as a participant has left and was on large
|
// we should act as a participant has left and was on large
|
||||||
// and we should choose somebody (electLastVisibleVideo)
|
// and we should choose somebody (electLastVisibleVideo)
|
||||||
this.updateLargeVideo(this.electLastVisibleVideo());
|
this.updateLargeVideo(this.electLastVisibleVideo());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update focused/pinned interface.
|
|
||||||
if (id) {
|
|
||||||
if (smallVideo && !interfaceConfig.filmStripOnly) {
|
|
||||||
smallVideo.focus(true);
|
|
||||||
this.pinParticipant(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateLargeVideo(id);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -684,12 +679,9 @@ const VideoLayout = {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
onDominantSpeakerChanged(id) {
|
onDominantSpeakerChanged(id) {
|
||||||
Object.values(remoteVideos).forEach(remoteVideo =>
|
getAllThumbnails().forEach(thumbnail =>
|
||||||
remoteVideo.showDominantSpeakerIndicator(
|
thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
|
||||||
id === remoteVideo.getId()));
|
|
||||||
|
|
||||||
localVideoThumbnail.showDominantSpeakerIndicator(
|
|
||||||
APP.conference.isLocalId(id));
|
|
||||||
|
|
||||||
if (!remoteVideos[id]) {
|
if (!remoteVideos[id]) {
|
||||||
return;
|
return;
|
||||||
|
@ -797,7 +789,7 @@ const VideoLayout = {
|
||||||
// Unlock large video
|
// Unlock large video
|
||||||
if (this.getPinnedId() === id) {
|
if (this.getPinnedId() === id) {
|
||||||
logger.info('Focused video owner has left the conference');
|
logger.info('Focused video owner has left the conference');
|
||||||
this.pinParticipant(null);
|
APP.store.dispatch(pinParticipant(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteVideo = remoteVideos[id];
|
const remoteVideo = remoteVideos[id];
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout.js';
|
// @flow
|
||||||
|
|
||||||
import { DOMINANT_SPEAKER_CHANGED } from '../base/participants';
|
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout.js';
|
||||||
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DOMINANT_SPEAKER_CHANGED,
|
||||||
|
PIN_PARTICIPANT
|
||||||
|
} from '../base/participants';
|
||||||
import { MiddlewareRegistry } from '../base/redux';
|
import { MiddlewareRegistry } from '../base/redux';
|
||||||
|
|
||||||
|
declare var APP: Object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Middleware which intercepts actions and updates the legacy component
|
* Middleware which intercepts actions and updates the legacy component
|
||||||
* {@code VideoLayout} as needed. The purpose of this middleware is to redux-ify
|
* {@code VideoLayout} as needed. The purpose of this middleware is to redux-ify
|
||||||
|
@ -13,12 +21,22 @@ import { MiddlewareRegistry } from '../base/redux';
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
MiddlewareRegistry.register(store => next => action => {
|
MiddlewareRegistry.register(store => next => action => {
|
||||||
|
// Purposefully perform additional actions after state update to mimic
|
||||||
|
// being connected to the store for updates.
|
||||||
const result = next(action);
|
const result = next(action);
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case DOMINANT_SPEAKER_CHANGED:
|
case DOMINANT_SPEAKER_CHANGED:
|
||||||
VideoLayout.onDominantSpeakerChanged(action.participant.id);
|
VideoLayout.onDominantSpeakerChanged(action.participant.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PIN_PARTICIPANT:
|
||||||
|
VideoLayout.onPinChange(action.participant.id);
|
||||||
|
APP.UI.emitEvent(
|
||||||
|
UIEvents.PINNED_ENDPOINT,
|
||||||
|
action.participant.id,
|
||||||
|
Boolean(action.participant.id));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Reference in New Issue