feat(pinning): move web pinning logic into redux

- Re-use the native redux pinning implementation for web
- Remove pinning logic from conference.js
- To the native pinning add a check for sharedVideo so
  youtube videos do not send a pin event
- Add shared videos as a participant to enable pinning and
  so they can eventually get added to the filmstrip
- Emit UIEvents.PINNED_ENDPOINT from middleware
This commit is contained in:
Leonard Kim
2017-08-11 10:43:35 +01:00
committed by Paweł Domas
parent 19d9b3f023
commit f1f46e0af5
8 changed files with 104 additions and 63 deletions
+30 -5
View File
@@ -2,10 +2,12 @@
import UIEvents from '../../../../service/UI/UIEvents';
import { CONNECTION_ESTABLISHED } from '../connection';
import JitsiMeetJS from '../lib-jitsi-meet';
import { setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../media';
import {
getLocalParticipant,
getParticipantById,
getPinnedParticipant,
PIN_PARTICIPANT
} from '../participants';
import { MiddlewareRegistry } from '../redux';
@@ -168,27 +170,46 @@ function _conferenceJoined(store, next, action) {
*/
function _pinParticipant(store, next, action) {
const state = store.getState();
const { conference } = state['features/base/conference'];
const participants = state['features/base/participants'];
const id = action.participant.id;
const participantById = getParticipantById(participants, id);
let pin;
// The following condition prevents signaling to pin local participant. The
// logic is:
const shouldEmitToLegacyApp = typeof APP !== 'undefined';
if (shouldEmitToLegacyApp) {
const pinnedParticipant = getPinnedParticipant(participants);
const actionName = action.participant.id ? 'pinned' : 'unpinned';
let videoType;
if ((participantById && participantById.local)
|| (!id && pinnedParticipant && pinnedParticipant.local)) {
videoType = 'local';
} else {
videoType = 'remote';
}
JitsiMeetJS.analytics.sendEvent(
`${actionName}.${videoType}`,
{ value: conference.getParticipantCount() });
}
// The following condition prevents signaling to pin local participant and
// shared videos. The logic is:
// - If we have an ID, we check if the participant identified by that ID is
// local.
// local or a bot/fake participant (such as with shared video).
// - If we don't have an ID (i.e. no participant identified by an ID), we
// check for local participant. If she's currently pinned, then this
// action will unpin her and that's why we won't signal here too.
if (participantById) {
pin = !participantById.local;
pin = !participantById.local && !participantById.isBot;
} else {
const localParticipant = getLocalParticipant(participants);
pin = !localParticipant || !localParticipant.pinned;
}
if (pin) {
const { conference } = state['features/base/conference'];
try {
conference.pinParticipant(id);
@@ -197,6 +218,10 @@ function _pinParticipant(store, next, action) {
}
}
if (shouldEmitToLegacyApp) {
APP.UI.emitEvent(UIEvents.PINNED_ENDPOINT, id, Boolean(id));
}
return next(action);
}
@@ -98,6 +98,38 @@ export function getParticipantById(stateOrGetState, id) {
return participants.find(p => p.id === id);
}
/**
* Returns a count of the known participants in the passed in redux state,
* excluding any fake participants.
*
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
* features/base/participants, the (whole) redux state, or redux's
* {@code getState} function to be used to retrieve the
* features/base/participants state.
* @returns {number}
*/
export function getParticipantCount(stateOrGetState) {
const participants = _getParticipants(stateOrGetState);
const realParticipants = participants.filter(p => !p.isBot);
return realParticipants.length;
}
/**
* Returns the participant which has its pinned state set to truthy.
*
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
* features/base/participants, the (whole) redux state, or redux's
* {@code getState} function to be used to retrieve the
* features/base/participants state.
* @returns {(Participant|undefined)}
*/
export function getPinnedParticipant(stateOrGetState) {
const participants = _getParticipants(stateOrGetState);
return participants.find(p => p.pinned);
}
/**
* Returns array of participants from Redux state.
*
@@ -73,6 +73,7 @@ function _participant(state, action) {
connectionStatus,
dominantSpeaker,
email,
isBot,
local,
pinned,
role
@@ -108,6 +109,7 @@ function _participant(state, action) {
dominantSpeaker: dominantSpeaker || false,
email,
id,
isBot,
local: local || false,
name,
pinned: pinned || false,
+7 -8
View File
@@ -9,7 +9,11 @@ import {
import { SET_CONFIG } from '../base/config';
import { SET_LOCATION_URL } from '../base/connection';
import { LIB_INIT_ERROR } from '../base/lib-jitsi-meet';
import { PARTICIPANT_JOINED } from '../base/participants';
import {
getLocalParticipant,
getParticipantCount,
PARTICIPANT_JOINED
} from '../base/participants';
import { MiddlewareRegistry } from '../base/redux';
import { setCallOverlayVisible, setJWT } from './actions';
@@ -96,13 +100,8 @@ function _maybeSetCallOverlayVisible({ dispatch, getState }, next, action) {
default: {
// The CallOverlay it to no longer be displayed/visible as soon
// as another participant joins.
const participants = state['features/base/participants'];
callOverlayVisible
= Boolean(
participants
&& participants.length === 1
&& participants[0].local);
callOverlayVisible = getParticipantCount(state) === 1
&& Boolean(getLocalParticipant(state));
// However, the CallDialog is not to be displayed/visible again
// after all remote participants leave.