feat: auto tile view
This commit is contained in:
parent
00b41dbb41
commit
240b033e76
|
@ -17,6 +17,7 @@ import {
|
|||
getToolboxHeight,
|
||||
showToolbox
|
||||
} from '../../../react/features/toolbox';
|
||||
import { YOUTUBE_PARTICIPANT_NAME } from '../../../react/features/youtube-player';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
import Filmstrip from '../videolayout/Filmstrip';
|
||||
|
@ -305,7 +306,7 @@ export default class SharedVideoManager {
|
|||
conference: APP.conference._room,
|
||||
id: self.url,
|
||||
isFakeParticipant: true,
|
||||
name: 'YouTube'
|
||||
name: YOUTUBE_PARTICIPANT_NAME
|
||||
}));
|
||||
|
||||
APP.store.dispatch(pinParticipant(self.url));
|
||||
|
|
|
@ -451,7 +451,7 @@ export default class SmallVideo {
|
|||
*/
|
||||
selectDisplayMode(input) {
|
||||
// Display name is always and only displayed when user is on the stage
|
||||
if (input.isCurrentlyOnLargeVideo && !input.tileViewEnabled) {
|
||||
if (input.isCurrentlyOnLargeVideo && !input.tileViewActive) {
|
||||
return input.isVideoPlayable && !input.isAudioOnly ? DISPLAY_BLACKNESS_WITH_NAME : DISPLAY_AVATAR_WITH_NAME;
|
||||
} else if (input.isVideoPlayable && input.hasVideo && !input.isAudioOnly) {
|
||||
// check hovering and change state to video with name
|
||||
|
@ -472,7 +472,7 @@ export default class SmallVideo {
|
|||
isCurrentlyOnLargeVideo: this.isCurrentlyOnLargeVideo(),
|
||||
isHovered: this._isHovered(),
|
||||
isAudioOnly: APP.conference.isAudioOnly(),
|
||||
tileViewEnabled: shouldDisplayTileView(APP.store.getState()),
|
||||
tileViewActive: shouldDisplayTileView(APP.store.getState()),
|
||||
isVideoPlayable: this.isVideoPlayable(),
|
||||
hasVideo: Boolean(this.selectVideoElement().length),
|
||||
connectionStatus: APP.conference.getParticipantConnectionStatus(this.id),
|
||||
|
|
|
@ -4,6 +4,7 @@ import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
|
|||
import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
|
||||
import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
|
||||
import { SCREEN_SHARE_PARTICIPANTS_UPDATED, SET_TILE_VIEW } from '../../video-layout/actionTypes';
|
||||
import { shouldDisplayTileView } from '../../video-layout/functions';
|
||||
import { SET_AUDIO_ONLY } from '../audio-only/actionTypes';
|
||||
import { CONFERENCE_JOINED } from '../conference/actionTypes';
|
||||
import { getParticipantById } from '../participants/functions';
|
||||
|
@ -59,7 +60,8 @@ function _updateLastN({ getState }) {
|
|||
if (typeof appState !== 'undefined' && appState !== 'active') {
|
||||
lastN = 0;
|
||||
} else if (audioOnly) {
|
||||
const { screenShares, tileViewEnabled } = state['features/video-layout'];
|
||||
const { screenShares } = state['features/video-layout'];
|
||||
const tileViewEnabled = shouldDisplayTileView(state);
|
||||
const largeVideoParticipantId = state['features/large-video'].participantId;
|
||||
const largeVideoParticipant
|
||||
= largeVideoParticipantId ? getParticipantById(state, largeVideoParticipantId) : undefined;
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
isButtonEnabled,
|
||||
isToolboxVisible
|
||||
} from '../../../toolbox';
|
||||
import { shouldDisplayTileView } from '../../../video-layout/functions';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
|
@ -83,7 +84,7 @@ function mapStateToProps(state) {
|
|||
const hide = interfaceConfig.HIDE_INVITE_MORE_HEADER;
|
||||
|
||||
return {
|
||||
_tileViewEnabled: state['features/video-layout'].tileViewEnabled,
|
||||
_tileViewEnabled: shouldDisplayTileView(state),
|
||||
_visible: isToolboxVisible(state) && isButtonEnabled('invite') && isAlone && !hide
|
||||
};
|
||||
}
|
||||
|
|
|
@ -152,17 +152,14 @@ function _onFollowMeCommand(attributes = {}, id, store) {
|
|||
}
|
||||
}
|
||||
|
||||
const pinnedParticipant
|
||||
= getPinnedParticipant(state, attributes.nextOnStage);
|
||||
const pinnedParticipant = getPinnedParticipant(state);
|
||||
const idOfParticipantToPin = attributes.nextOnStage;
|
||||
|
||||
if (typeof idOfParticipantToPin !== 'undefined'
|
||||
&& (!pinnedParticipant
|
||||
|| idOfParticipantToPin !== pinnedParticipant.id)
|
||||
&& (!pinnedParticipant || idOfParticipantToPin !== pinnedParticipant.id)
|
||||
&& oldState.nextOnStage !== attributes.nextOnStage) {
|
||||
_pinVideoThumbnailById(store, idOfParticipantToPin);
|
||||
} else if (typeof idOfParticipantToPin === 'undefined'
|
||||
&& pinnedParticipant) {
|
||||
} else if (typeof idOfParticipantToPin === 'undefined' && pinnedParticipant) {
|
||||
store.dispatch(pinParticipant(null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
isLocalParticipantModerator
|
||||
} from '../base/participants';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import { shouldDisplayTileView } from '../video-layout/functions';
|
||||
|
||||
import { FOLLOW_ME_COMMAND } from './constants';
|
||||
|
||||
|
@ -72,7 +73,7 @@ function _getFollowMeState(state) {
|
|||
filmstripVisible: state['features/filmstrip'].visible,
|
||||
nextOnStage: pinnedParticipant && pinnedParticipant.id,
|
||||
sharedDocumentVisible: state['features/etherpad'].editing,
|
||||
tileViewEnabled: state['features/video-layout'].tileViewEnabled
|
||||
tileViewEnabled: shouldDisplayTileView(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconPin } from '../../../base/icons';
|
|||
import { pinParticipant } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox';
|
||||
import { shouldDisplayTileView } from '../../../video-layout/functions';
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
|
||||
|
@ -59,7 +60,7 @@ class PinButton extends AbstractButton<Props, *> {
|
|||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
visible: state['features/video-layout'].tileViewEnabled
|
||||
visible: shouldDisplayTileView(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ import {
|
|||
} from '../../../subtitles';
|
||||
import {
|
||||
TileViewButton,
|
||||
shouldDisplayTileView,
|
||||
toggleTileView
|
||||
} from '../../../video-layout';
|
||||
import {
|
||||
|
@ -1416,7 +1417,7 @@ function _mapStateToProps(state) {
|
|||
_feedbackConfigured: Boolean(callStatsID),
|
||||
_isGuest: state['features/base/jwt'].isGuest,
|
||||
_fullScreen: fullScreen,
|
||||
_tileViewEnabled: state['features/video-layout'].tileViewEnabled,
|
||||
_tileViewEnabled: shouldDisplayTileView(state),
|
||||
_localParticipantID: localParticipant.id,
|
||||
_localRecState: localRecordingStates,
|
||||
_locked: locked,
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
SCREEN_SHARE_PARTICIPANTS_UPDATED,
|
||||
SET_TILE_VIEW
|
||||
} from './actionTypes';
|
||||
import { shouldDisplayTileView } from './functions';
|
||||
|
||||
/**
|
||||
* Creates a (redux) action which signals that the list of known participants
|
||||
|
@ -32,10 +33,10 @@ export function setParticipantsWithScreenShare(participantIds: Array<string>) {
|
|||
* @param {boolean} enabled - Whether or not tile view should be shown.
|
||||
* @returns {{
|
||||
* type: SET_TILE_VIEW,
|
||||
* enabled: boolean
|
||||
* enabled: ?boolean
|
||||
* }}
|
||||
*/
|
||||
export function setTileView(enabled: boolean) {
|
||||
export function setTileView(enabled: ?boolean) {
|
||||
return {
|
||||
type: SET_TILE_VIEW,
|
||||
enabled
|
||||
|
@ -50,8 +51,8 @@ export function setTileView(enabled: boolean) {
|
|||
*/
|
||||
export function toggleTileView() {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const { tileViewEnabled } = getState()['features/video-layout'];
|
||||
const tileViewActive = shouldDisplayTileView(getState());
|
||||
|
||||
dispatch(setTileView(!tileViewEnabled));
|
||||
dispatch(setTileView(!tileViewActive));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,12 +9,14 @@ import {
|
|||
import { TILE_VIEW_ENABLED, getFeatureFlag } from '../../base/flags';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { IconTileView } from '../../base/icons';
|
||||
import { getParticipantCount } from '../../base/participants';
|
||||
import { connect } from '../../base/redux';
|
||||
import {
|
||||
AbstractButton,
|
||||
type AbstractButtonProps
|
||||
} from '../../base/toolbox';
|
||||
import { setTileView } from '../actions';
|
||||
import { shouldDisplayTileView } from '../functions';
|
||||
import logger from '../logger';
|
||||
|
||||
/**
|
||||
|
@ -88,10 +90,11 @@ class TileViewButton<P: Props> extends AbstractButton<P, *> {
|
|||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
const enabled = getFeatureFlag(state, TILE_VIEW_ENABLED, true);
|
||||
const { visible = enabled } = ownProps;
|
||||
const lonelyMeeting = getParticipantCount(state) < 2;
|
||||
const { visible = enabled && !lonelyMeeting } = ownProps;
|
||||
|
||||
return {
|
||||
_tileViewEnabled: state['features/video-layout'].tileViewEnabled,
|
||||
_tileViewEnabled: shouldDisplayTileView(state),
|
||||
visible
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import { getPinnedParticipant } from '../base/participants';
|
||||
import { getPinnedParticipant, getParticipantCount } from '../base/participants';
|
||||
import { isYoutubeVideoPlaying } from '../youtube-player';
|
||||
|
||||
import { LAYOUTS } from './constants';
|
||||
|
||||
|
@ -72,17 +73,44 @@ export function getTileViewGridDimensions(state: Object, maxColumns: number = ge
|
|||
* @returns {boolean} True if tile view should be displayed.
|
||||
*/
|
||||
export function shouldDisplayTileView(state: Object = {}) {
|
||||
return Boolean(
|
||||
state['features/video-layout']
|
||||
&& state['features/video-layout'].tileViewEnabled
|
||||
&& (!state['features/etherpad']
|
||||
|| !state['features/etherpad'].editing)
|
||||
const participantCount = getParticipantCount(state);
|
||||
|
||||
// Truthy check is needed for interfaceConfig to prevent errors on
|
||||
// mobile which does not have interfaceConfig. On web, tile view
|
||||
// should never be enabled for filmstrip only mode.
|
||||
&& (typeof interfaceConfig === 'undefined'
|
||||
|| !interfaceConfig.filmStripOnly)
|
||||
&& !getPinnedParticipant(state)
|
||||
// In case of a lonely meeting, we don't allow tile view.
|
||||
// But it's a special case too, as we don't even render the button,
|
||||
// see TileViewButton component.
|
||||
if (participantCount < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { tileViewEnabled } = state['features/video-layout'];
|
||||
|
||||
if (tileViewEnabled !== undefined) {
|
||||
// If the user explicitly requested a view mode, we
|
||||
// do that.
|
||||
return tileViewEnabled;
|
||||
}
|
||||
|
||||
// None tile view mode is easier to calculate (no need for many negations), so we do
|
||||
// that and negate it only once.
|
||||
const shouldDisplayNormalMode = Boolean(
|
||||
|
||||
// Reasons for normal mode:
|
||||
|
||||
// Editing etherpad
|
||||
state['features/etherpad']?.editing
|
||||
|
||||
// We're in filmstrip-only mode
|
||||
|| (typeof interfaceConfig === 'object' && interfaceConfig?.filmStripOnly)
|
||||
|
||||
// We pinned a participant
|
||||
|| getPinnedParticipant(state)
|
||||
|
||||
// It's a 1-on-1 meeting
|
||||
|| participantCount < 3
|
||||
|
||||
// There is a shared YouTube video in the meeting
|
||||
|| isYoutubeVideoPlaying(state)
|
||||
);
|
||||
|
||||
return !shouldDisplayNormalMode;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import {
|
||||
PIN_PARTICIPANT,
|
||||
getPinnedParticipant,
|
||||
pinParticipant
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { SET_DOCUMENT_EDITING_STATUS, toggleDocument } from '../etherpad';
|
||||
// @flow
|
||||
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { PIN_PARTICIPANT, pinParticipant, getPinnedParticipant } from '../base/participants';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import { SET_DOCUMENT_EDITING_STATUS } from '../etherpad';
|
||||
|
||||
import { SET_TILE_VIEW } from './actionTypes';
|
||||
import { setTileView } from './actions';
|
||||
|
||||
import './subscriber';
|
||||
|
||||
let previousTileViewEnabled;
|
||||
|
||||
/**
|
||||
* Middleware which intercepts actions and updates tile view related state.
|
||||
*
|
||||
|
@ -18,41 +19,82 @@ import './subscriber';
|
|||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
// Actions that temporarily clear the user preferred state of tile view,
|
||||
// then re-set it when needed.
|
||||
case PIN_PARTICIPANT: {
|
||||
const isPinning = Boolean(action.participant.id);
|
||||
const { tileViewEnabled } = store.getState()['features/video-layout'];
|
||||
const pinnedParticipant = getPinnedParticipant(store.getState());
|
||||
|
||||
if (isPinning && tileViewEnabled) {
|
||||
store.dispatch(setTileView(false));
|
||||
if (pinnedParticipant) {
|
||||
_storeTileViewStateAndClear(store);
|
||||
} else {
|
||||
_restoreTileViewState(store);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_DOCUMENT_EDITING_STATUS:
|
||||
if (action.editing) {
|
||||
store.dispatch(setTileView(false));
|
||||
_storeTileViewStateAndClear(store);
|
||||
} else {
|
||||
_restoreTileViewState(store);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SET_TILE_VIEW: {
|
||||
const state = store.getState();
|
||||
|
||||
if (action.enabled) {
|
||||
if (getPinnedParticipant(state)) {
|
||||
store.dispatch(pinParticipant(null));
|
||||
}
|
||||
|
||||
if (state['features/etherpad'].editing) {
|
||||
store.dispatch(toggleDocument());
|
||||
}
|
||||
// Things to update when tile view state changes
|
||||
case SET_TILE_VIEW:
|
||||
if (action.enabled && getPinnedParticipant(store)) {
|
||||
store.dispatch(pinParticipant(null));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up state change listener to perform maintenance tasks when the conference
|
||||
* is left or failed.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch }, previousConference) => {
|
||||
if (conference !== previousConference) {
|
||||
// conference changed, left or failed...
|
||||
// Clear tile view state.
|
||||
dispatch(setTileView());
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Respores tile view state, if it wasn't updated since then.
|
||||
*
|
||||
* @param {Object} store - The Redux Store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _restoreTileViewState({ dispatch, getState }) {
|
||||
const { tileViewEnabled } = getState()['features/video-layout'];
|
||||
|
||||
if (tileViewEnabled === undefined && previousTileViewEnabled !== undefined) {
|
||||
dispatch(setTileView(previousTileViewEnabled));
|
||||
}
|
||||
|
||||
previousTileViewEnabled = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current tile view state and clears it.
|
||||
*
|
||||
* @param {Object} store - The Redux Store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _storeTileViewStateAndClear({ dispatch, getState }) {
|
||||
const { tileViewEnabled } = getState()['features/video-layout'];
|
||||
|
||||
if (tileViewEnabled !== undefined) {
|
||||
previousTileViewEnabled = tileViewEnabled;
|
||||
dispatch(setTileView(undefined));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
break;
|
||||
|
||||
case PIN_PARTICIPANT:
|
||||
VideoLayout.onPinChange(action.participant.id);
|
||||
VideoLayout.onPinChange(action.participant?.id);
|
||||
break;
|
||||
|
||||
case SET_FILMSTRIP_VISIBLE:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { PersistenceRegistry, ReducerRegistry } from '../base/redux';
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
SCREEN_SHARE_PARTICIPANTS_UPDATED,
|
||||
|
@ -14,18 +14,17 @@ const DEFAULT_STATE = {
|
|||
* The indicator which determines whether the video layout should display
|
||||
* video thumbnails in a tiled layout.
|
||||
*
|
||||
* Note: undefined means that the user hasn't requested anything in particular yet, so
|
||||
* we use our auto switching rules.
|
||||
*
|
||||
* @public
|
||||
* @type {boolean}
|
||||
*/
|
||||
tileViewEnabled: false
|
||||
tileViewEnabled: undefined
|
||||
};
|
||||
|
||||
const STORE_NAME = 'features/video-layout';
|
||||
|
||||
PersistenceRegistry.register(STORE_NAME, {
|
||||
tileViewEnabled: true
|
||||
});
|
||||
|
||||
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case SCREEN_SHARE_PARTICIPANTS_UPDATED: {
|
||||
|
|
|
@ -2,16 +2,12 @@
|
|||
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import {
|
||||
getPinnedParticipant,
|
||||
pinParticipant
|
||||
} from '../base/participants';
|
||||
import { pinParticipant, getPinnedParticipant } from '../base/participants';
|
||||
import { StateListenerRegistry, equals } from '../base/redux';
|
||||
import { isFollowMeActive } from '../follow-me';
|
||||
import { selectParticipant } from '../large-video';
|
||||
|
||||
import { setParticipantsWithScreenShare } from './actions';
|
||||
import { shouldDisplayTileView } from './functions';
|
||||
|
||||
declare var APP: Object;
|
||||
declare var interfaceConfig: Object;
|
||||
|
@ -21,17 +17,11 @@ declare var interfaceConfig: Object;
|
|||
* preferred layout state and dispatching additional actions.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => shouldDisplayTileView(state),
|
||||
/* listener */ (displayTileView, store) => {
|
||||
/* selector */ state => state['features/video-layout'].tileViewEnabled,
|
||||
/* listener */ (tileViewEnabled, store) => {
|
||||
const { dispatch } = store;
|
||||
|
||||
dispatch(selectParticipant());
|
||||
|
||||
if (!displayTileView) {
|
||||
if (_getAutoPinSetting()) {
|
||||
_updateAutoPinnedParticipant(store);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -115,9 +105,11 @@ function _updateAutoPinnedParticipant({ dispatch, getState }) {
|
|||
const latestScreenshareParticipantId
|
||||
= screenShares[screenShares.length - 1];
|
||||
|
||||
const pinned = getPinnedParticipant(getState);
|
||||
|
||||
if (latestScreenshareParticipantId) {
|
||||
dispatch(pinParticipant(latestScreenshareParticipantId));
|
||||
} else if (getPinnedParticipant(state['features/base/participants'])) {
|
||||
} else if (pinned) {
|
||||
dispatch(pinParticipant(null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { Component } from 'react';
|
||||
|
||||
export { Component as EnterVideoLinkPrompt };
|
||||
export { Component as YoutubeLargeVideo };
|
|
@ -1,3 +1,5 @@
|
|||
// @flow
|
||||
|
||||
export { default as VideoShareButton } from './VideoShareButton';
|
||||
|
||||
export * from './_';
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
// @flow
|
||||
|
||||
export { default as EnterVideoLinkPrompt } from './EnterVideoLinkPrompt';
|
||||
export { default as YoutubeLargeVideo } from './YoutubeLargeVideo';
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* Fixed name of the YouTube player fake participant.
|
||||
*/
|
||||
export const YOUTUBE_PARTICIPANT_NAME = 'YouTube';
|
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
|
||||
import { getParticipants } from '../base/participants';
|
||||
|
||||
import { YOUTUBE_PARTICIPANT_NAME } from './constants';
|
||||
|
||||
/**
|
||||
* Returns true if there is a youtube video being shaerd in the meeting.
|
||||
*
|
||||
* @param {Object | Function} stateful - The Redux state or a function that gets resolved to the Redux state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isYoutubeVideoPlaying(stateful: Object | Function): boolean {
|
||||
return Boolean(getParticipants(stateful).find(p => p.isFakeParticipant && p.name === YOUTUBE_PARTICIPANT_NAME));
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
// @flow
|
||||
|
||||
export * from './actions';
|
||||
export * from './actionTypes';
|
||||
export * from './components';
|
||||
export * from './constants';
|
||||
export * from './functions';
|
||||
|
|
|
@ -12,6 +12,7 @@ import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
|||
|
||||
import { TOGGLE_SHARED_VIDEO, SET_SHARED_VIDEO_STATUS } from './actionTypes';
|
||||
import { setSharedVideoStatus, showEnterVideoLinkPrompt } from './actions';
|
||||
import { YOUTUBE_PARTICIPANT_NAME } from './constants';
|
||||
|
||||
const SHARED_VIDEO = 'shared-video';
|
||||
|
||||
|
@ -105,7 +106,7 @@ function handleSharingVideoStatus(store, videoId, { state, time, from }, confere
|
|||
id: videoId,
|
||||
isFakeParticipant: true,
|
||||
avatarURL: `https://img.youtube.com/vi/${videoId}/0.jpg`,
|
||||
name: 'YouTube'
|
||||
name: YOUTUBE_PARTICIPANT_NAME
|
||||
}));
|
||||
|
||||
dispatch(pinParticipant(videoId));
|
||||
|
|
Loading…
Reference in New Issue