ref(video-layout): get pinned ID directly from redux

This commit is contained in:
Leonard Kim 2018-05-18 12:59:07 -07:00 committed by virtuacoplenny
parent 57f7abc6dd
commit 05801711a7
9 changed files with 110 additions and 76 deletions

View File

@ -1,3 +1,5 @@
/* global APP */
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
@ -15,6 +17,10 @@
*/
const logger = require('jitsi-meet-logger').getLogger(__filename);
import {
getPinnedParticipant,
pinParticipant
} from '../react/features/base/participants';
import UIEvents from '../service/UI/UIEvents';
import VideoLayout from './UI/videolayout/VideoLayout';
@ -444,11 +450,15 @@ class FollowMe {
if (smallVideo) {
this.nextOnStageTimer = 0;
clearTimeout(this.nextOnStageTimout);
/* eslint-disable no-mixed-operators */
if (pin && !VideoLayout.isPinned(clickId)
|| !pin && VideoLayout.isPinned(clickId)) {
/* eslint-disable no-mixed-operators */
VideoLayout.handleVideoThumbClicked(clickId);
if (pin) {
APP.store.dispatch(pinParticipant(clickId));
} else {
const { id } = getPinnedParticipant(APP.store.getState()) || {};
if (id === clickId) {
APP.store.dispatch(pinParticipant(null));
}
}
} else {
// If there's no SmallVideo object for the given id, lets wait and

View File

@ -959,15 +959,6 @@ UI.getLargeVideo = function() {
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"
* 2 button dialog with buttons - cancel and go to web store.

View File

@ -317,7 +317,7 @@ export default class SharedVideoManager {
name: 'YouTube'
}));
VideoLayout.handleVideoThumbClicked(self.url);
thumb.videoClick();
// If we are sending the command and we are starting the player
// we need to continuously send the player current time position

View File

@ -59,7 +59,7 @@ SharedVideoThumb.prototype.createContainer = function(spanId) {
* The thumb click handler.
*/
SharedVideoThumb.prototype.videoClick = function() {
this.VideoLayout.handleVideoThumbClicked(this.url);
this._togglePin();
};
/**

View File

@ -260,7 +260,7 @@ LocalVideo.prototype._onContainerClick = function(event) {
}
if (!ignoreClick) {
this.VideoLayout.handleVideoThumbClicked(this.id);
this._togglePin();
}
};

View File

@ -11,7 +11,10 @@ import { i18next } from '../../../react/features/base/i18n';
import {
JitsiParticipantConnectionStatus
} from '../../../react/features/base/lib-jitsi-meet';
import {
getPinnedParticipant,
pinParticipant
} from '../../../react/features/base/participants';
import { PresenceLabel } from '../../../react/features/presence-status';
import {
REMOTE_CONTROL_MENU_STATES,
@ -234,10 +237,12 @@ RemoteVideo.prototype._requestRemoteControlPermissions = function() {
if (result === true) {
// the remote control permissions has been granted
// pin the controlled participant
const pinnedId = this.VideoLayout.getPinnedId();
const pinnedParticipant
= getPinnedParticipant(APP.store.getState()) || {};
const pinnedId = pinnedParticipant.id;
if (pinnedId !== this.id) {
this.VideoLayout.handleVideoThumbClicked(this.id);
APP.store.dispatch(pinParticipant(this.id));
}
}
}, error => {
@ -648,7 +653,7 @@ RemoteVideo.prototype._onContainerClick = function(event) {
|| classList.contains('popover');
if (!ignoreClick) {
this.VideoLayout.handleVideoThumbClicked(this.id);
this._togglePin();
}
// On IE we need to populate this handler on video <object> and it does not

View File

@ -12,7 +12,9 @@ import { AudioLevelIndicator }
from '../../../react/features/audio-level-indicator';
import {
Avatar as AvatarDisplay,
getAvatarURLByParticipantId
getAvatarURLByParticipantId,
getPinnedParticipant,
pinParticipant
} from '../../../react/features/base/participants';
import {
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
* speaker, and raised hand icons.

View File

@ -5,7 +5,6 @@ import {
JitsiParticipantConnectionStatus
} from '../../../react/features/base/lib-jitsi-meet';
import {
getParticipants,
getPinnedParticipant,
pinParticipant
} 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
* speaker.
@ -50,7 +72,7 @@ function onLocalFlipXChanged(val) {
* @returns {string|null}
*/
function getCurrentRemoteDominantSpeakerID() {
const dominantSpeaker = getParticipants(APP.store.getState)
const dominantSpeaker = getAllParticipants()
.find(participant => participant.dominantSpeaker);
if (dominantSpeaker) {
@ -93,8 +115,6 @@ const VideoLayout = {
// the local video thumb maybe one pixel
this.resizeThumbnails(true);
this.handleVideoThumbClicked = this.handleVideoThumbClicked.bind(this);
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
* pinned. Pass in null to unpin without pinning another participant.
* @paramn {string|null} pinnedParticipantID - The participant ID of the
* participant that is pinned or null if no one is pinned.
* @returns {void}
*/
pinParticipant(id) {
APP.store.dispatch(pinParticipant(id));
APP.UI.emitEvent(UIEvents.PINNED_ENDPOINT, id, Boolean(id));
},
/**
* 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);
}
onPinChange(pinnedParticipantID) {
if (interfaceConfig.filmStripOnly) {
return;
}
// Unpin if currently pinned.
if (pinnedId === id) {
this.pinParticipant(null);
getAllThumbnails().forEach(thumbnail =>
thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
// Enable the currently set dominant speaker.
if (getCurrentRemoteDominantSpeakerID()) {
this.updateLargeVideo(getCurrentRemoteDominantSpeakerID());
if (pinnedParticipantID) {
this.updateLargeVideo(pinnedParticipantID);
} else {
const currentDominantSpeakerID
= getCurrentRemoteDominantSpeakerID();
if (currentDominantSpeakerID) {
this.updateLargeVideo(currentDominantSpeakerID);
} else {
// if there is no currentDominantSpeaker, it can also be
// if there is no currentDominantSpeakerID, it can also be
// that local participant is the dominant speaker
// we should act as a participant has left and was on large
// and we should choose somebody (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}
*/
onDominantSpeakerChanged(id) {
Object.values(remoteVideos).forEach(remoteVideo =>
remoteVideo.showDominantSpeakerIndicator(
id === remoteVideo.getId()));
getAllThumbnails().forEach(thumbnail =>
thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
localVideoThumbnail.showDominantSpeakerIndicator(
APP.conference.isLocalId(id));
if (!remoteVideos[id]) {
return;
@ -797,7 +789,7 @@ const VideoLayout = {
// Unlock large video
if (this.getPinnedId() === id) {
logger.info('Focused video owner has left the conference');
this.pinParticipant(null);
APP.store.dispatch(pinParticipant(null));
}
const remoteVideo = remoteVideos[id];

View File

@ -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';
declare var APP: Object;
/**
* Middleware which intercepts actions and updates the legacy component
* {@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
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);
switch (action.type) {
case DOMINANT_SPEAKER_CHANGED:
VideoLayout.onDominantSpeakerChanged(action.participant.id);
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;