|
|
|
@ -1,11 +1,13 @@ |
|
|
|
|
// @flow
|
|
|
|
|
|
|
|
|
|
/* eslint-disable lines-around-comment */ |
|
|
|
|
import { IState } from '../app/types'; |
|
|
|
|
import { |
|
|
|
|
isParticipantApproved, |
|
|
|
|
isEnabledFromState, |
|
|
|
|
isLocalParticipantApprovedFromState, |
|
|
|
|
isSupported |
|
|
|
|
} from '../av-moderation/functions'; |
|
|
|
|
import { IStateful } from '../base/app/types'; |
|
|
|
|
// @ts-ignore
|
|
|
|
|
import { getFeatureFlag, INVITE_ENABLED } from '../base/flags'; |
|
|
|
|
import { MEDIA_TYPE, type MediaType } from '../base/media/constants'; |
|
|
|
|
import { |
|
|
|
@ -16,7 +18,9 @@ import { |
|
|
|
|
getRemoteParticipantsSorted, |
|
|
|
|
getRaiseHandsQueue |
|
|
|
|
} from '../base/participants/functions'; |
|
|
|
|
import { toState } from '../base/redux'; |
|
|
|
|
import { Participant } from '../base/participants/types'; |
|
|
|
|
import { toState } from '../base/redux/functions'; |
|
|
|
|
// @ts-ignore
|
|
|
|
|
import { normalizeAccents } from '../base/util/strings'; |
|
|
|
|
import { isInBreakoutRoom } from '../breakout-rooms/functions'; |
|
|
|
|
|
|
|
|
@ -25,11 +29,11 @@ import { QUICK_ACTION_BUTTON, REDUCER_KEY, MEDIA_STATE } from './constants'; |
|
|
|
|
/** |
|
|
|
|
* Find the first styled ancestor component of an element. |
|
|
|
|
* |
|
|
|
|
* @param {Element} target - Element to look up. |
|
|
|
|
* @param {HTMLElement|null} target - Element to look up. |
|
|
|
|
* @param {string} cssClass - Styled component reference. |
|
|
|
|
* @returns {Element|null} Ancestor. |
|
|
|
|
* @returns {HTMLElement|null} Ancestor. |
|
|
|
|
*/ |
|
|
|
|
export const findAncestorByClass = (target: Object, cssClass: string) => { |
|
|
|
|
export const findAncestorByClass = (target: HTMLElement | null, cssClass: string): HTMLElement | null => { |
|
|
|
|
if (!target || target.classList.contains(cssClass)) { |
|
|
|
|
return target; |
|
|
|
|
} |
|
|
|
@ -40,14 +44,14 @@ export const findAncestorByClass = (target: Object, cssClass: string) => { |
|
|
|
|
/** |
|
|
|
|
* Checks if a participant is force muted. |
|
|
|
|
* |
|
|
|
|
* @param {Object} participant - The participant. |
|
|
|
|
* @param {Participant|undefined} participant - The participant. |
|
|
|
|
* @param {MediaType} mediaType - The media type. |
|
|
|
|
* @param {Object} state - The redux state. |
|
|
|
|
* @param {IState} state - The redux state. |
|
|
|
|
* @returns {MediaState} |
|
|
|
|
*/ |
|
|
|
|
export function isForceMuted(participant: Object, mediaType: MediaType, state: Object) { |
|
|
|
|
export function isForceMuted(participant: Participant | undefined, mediaType: MediaType, state: IState) { |
|
|
|
|
if (isEnabledFromState(mediaType, state)) { |
|
|
|
|
if (participant.local) { |
|
|
|
|
if (participant?.local) { |
|
|
|
|
return !isLocalParticipantApprovedFromState(mediaType, state); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -56,7 +60,7 @@ export function isForceMuted(participant: Object, mediaType: MediaType, state: O |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return !isParticipantApproved(participant.id, mediaType)(state); |
|
|
|
|
return !isParticipantApproved(participant?.id ?? '', mediaType)(state); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
@ -65,12 +69,12 @@ export function isForceMuted(participant: Object, mediaType: MediaType, state: O |
|
|
|
|
/** |
|
|
|
|
* Determines the audio media state (the mic icon) for a participant. |
|
|
|
|
* |
|
|
|
|
* @param {Object} participant - The participant. |
|
|
|
|
* @param {Participant} participant - The participant. |
|
|
|
|
* @param {boolean} muted - The mute state of the participant. |
|
|
|
|
* @param {Object} state - The redux state. |
|
|
|
|
* @param {IState} state - The redux state. |
|
|
|
|
* @returns {MediaState} |
|
|
|
|
*/ |
|
|
|
|
export function getParticipantAudioMediaState(participant: Object, muted: Boolean, state: Object) { |
|
|
|
|
export function getParticipantAudioMediaState(participant: Participant, muted: Boolean, state: IState) { |
|
|
|
|
const dominantSpeaker = getDominantSpeakerParticipant(state); |
|
|
|
|
|
|
|
|
|
if (muted) { |
|
|
|
@ -91,12 +95,12 @@ export function getParticipantAudioMediaState(participant: Object, muted: Boolea |
|
|
|
|
/** |
|
|
|
|
* Determines the video media state (the mic icon) for a participant. |
|
|
|
|
* |
|
|
|
|
* @param {Object} participant - The participant. |
|
|
|
|
* @param {Participant} participant - The participant. |
|
|
|
|
* @param {boolean} muted - The mute state of the participant. |
|
|
|
|
* @param {Object} state - The redux state. |
|
|
|
|
* @param {IState} state - The redux state. |
|
|
|
|
* @returns {MediaState} |
|
|
|
|
*/ |
|
|
|
|
export function getParticipantVideoMediaState(participant: Object, muted: Boolean, state: Object) { |
|
|
|
|
export function getParticipantVideoMediaState(participant: Participant, muted: Boolean, state: IState) { |
|
|
|
|
if (muted) { |
|
|
|
|
if (isForceMuted(participant, MEDIA_TYPE.VIDEO, state)) { |
|
|
|
|
return MEDIA_STATE.FORCE_MUTED; |
|
|
|
@ -116,7 +120,7 @@ export function getParticipantVideoMediaState(participant: Object, muted: Boolea |
|
|
|
|
* @param {string} name - Property name. |
|
|
|
|
* @returns {number} Float value. |
|
|
|
|
*/ |
|
|
|
|
export const getFloatStyleProperty = (styles: Object, name: string) => |
|
|
|
|
export const getFloatStyleProperty = (styles: CSSStyleDeclaration, name: string) => |
|
|
|
|
parseFloat(styles.getPropertyValue(name)); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -136,19 +140,19 @@ export const getComputedOuterHeight = (element: HTMLElement) => { |
|
|
|
|
/** |
|
|
|
|
* Returns this feature's root state. |
|
|
|
|
* |
|
|
|
|
* @param {Object} state - Global state. |
|
|
|
|
* @param {IState} state - Global state. |
|
|
|
|
* @returns {Object} Feature state. |
|
|
|
|
*/ |
|
|
|
|
const getState = (state: Object) => state[REDUCER_KEY]; |
|
|
|
|
const getState = (state: IState) => state[REDUCER_KEY]; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the participants pane config. |
|
|
|
|
* |
|
|
|
|
* @param {Function|Object} stateful - The redux store, the redux |
|
|
|
|
* @param {IStateful} stateful - The redux store, the redux |
|
|
|
|
* {@code getState} function, or the redux state itself. |
|
|
|
|
* @returns {Object} |
|
|
|
|
*/ |
|
|
|
|
export const getParticipantsPaneConfig = (stateful: Function | Object) => { |
|
|
|
|
export const getParticipantsPaneConfig = (stateful: IStateful) => { |
|
|
|
|
const state = toState(stateful); |
|
|
|
|
const { participantsPane = {} } = state['features/base/config']; |
|
|
|
|
|
|
|
|
@ -158,21 +162,21 @@ export const getParticipantsPaneConfig = (stateful: Function | Object) => { |
|
|
|
|
/** |
|
|
|
|
* Is the participants pane open. |
|
|
|
|
* |
|
|
|
|
* @param {Object} state - Global state. |
|
|
|
|
* @param {IState} state - Global state. |
|
|
|
|
* @returns {boolean} Is the participants pane open. |
|
|
|
|
*/ |
|
|
|
|
export const getParticipantsPaneOpen = (state: Object) => Boolean(getState(state)?.isOpen); |
|
|
|
|
export const getParticipantsPaneOpen = (state: IState) => Boolean(getState(state)?.isOpen); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the type of quick action button to be displayed for a participant. |
|
|
|
|
* The button is displayed when hovering a participant from the participant list. |
|
|
|
|
* |
|
|
|
|
* @param {Object} participant - The participant. |
|
|
|
|
* @param {Participant} participant - The participant. |
|
|
|
|
* @param {boolean} isAudioMuted - If audio is muted for the participant. |
|
|
|
|
* @param {Object} state - The redux state. |
|
|
|
|
* @param {IState} state - The redux state. |
|
|
|
|
* @returns {string} - The type of the quick action button. |
|
|
|
|
*/ |
|
|
|
|
export function getQuickActionButtonType(participant: Object, isAudioMuted: Boolean, state: Object) { |
|
|
|
|
export function getQuickActionButtonType(participant: Participant, isAudioMuted: Boolean, state: IState) { |
|
|
|
|
// handled only by moderators
|
|
|
|
|
if (isLocalParticipantModerator(state)) { |
|
|
|
|
if (!isAudioMuted) { |
|
|
|
@ -189,10 +193,10 @@ export function getQuickActionButtonType(participant: Object, isAudioMuted: Bool |
|
|
|
|
/** |
|
|
|
|
* Returns true if the invite button should be rendered. |
|
|
|
|
* |
|
|
|
|
* @param {Object} state - Global state. |
|
|
|
|
* @param {IState} state - Global state. |
|
|
|
|
* @returns {boolean} |
|
|
|
|
*/ |
|
|
|
|
export const shouldRenderInviteButton = (state: Object) => { |
|
|
|
|
export const shouldRenderInviteButton = (state: IState) => { |
|
|
|
|
const { disableInviteFunctions } = toState(state)['features/base/config']; |
|
|
|
|
const flagEnabled = getFeatureFlag(state, INVITE_ENABLED, true); |
|
|
|
|
const inBreakoutRoom = isInBreakoutRoom(state); |
|
|
|
@ -211,12 +215,12 @@ export const shouldRenderInviteButton = (state: Object) => { |
|
|
|
|
* 6. Recent speakers sorted alphabetically by their display name. |
|
|
|
|
* 7. Rest of the participants sorted alphabetically by their display name. |
|
|
|
|
* |
|
|
|
|
* @param {(Function|Object)} stateful - The (whole) redux state, or redux's |
|
|
|
|
* @param {IStateful} stateful - The (whole) redux state, or redux's |
|
|
|
|
* {@code getState} function to be used to retrieve the state features/base/participants. |
|
|
|
|
* @returns {Array<string>} |
|
|
|
|
*/ |
|
|
|
|
export function getSortedParticipantIds(stateful: Object | Function): Array<string> { |
|
|
|
|
const { id } = getLocalParticipant(stateful); |
|
|
|
|
export function getSortedParticipantIds(stateful: IStateful) { |
|
|
|
|
const id = getLocalParticipant(stateful)?.id; |
|
|
|
|
const remoteParticipants = getRemoteParticipantsSorted(stateful); |
|
|
|
|
const reorderedParticipants = new Set(remoteParticipants); |
|
|
|
|
const raisedHandParticipants = getRaiseHandsQueue(stateful).map(({ id: particId }) => particId); |
|
|
|
@ -232,7 +236,7 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri |
|
|
|
|
|
|
|
|
|
const dominant = []; |
|
|
|
|
const dominantId = dominantSpeaker?.id; |
|
|
|
|
const local = remoteRaisedHandParticipants.has(id) ? [] : [ id ]; |
|
|
|
|
const local = remoteRaisedHandParticipants.has(id ?? '') ? [] : [ id ]; |
|
|
|
|
|
|
|
|
|
// In case dominat speaker has raised hand, keep the order in the raised hand queue.
|
|
|
|
|
// In case they don't have raised hand, goes first in the participants list.
|
|
|
|
@ -257,7 +261,8 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri |
|
|
|
|
* @param {string} searchString - The participants search string. |
|
|
|
|
* @returns {boolean} |
|
|
|
|
*/ |
|
|
|
|
export function participantMatchesSearch(participant: Object, searchString: string) { |
|
|
|
|
export function participantMatchesSearch(participant: { displayName: string; jid: string; name?: string; }, |
|
|
|
|
searchString: string) { |
|
|
|
|
if (searchString === '') { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -279,10 +284,10 @@ export function participantMatchesSearch(participant: Object, searchString: stri |
|
|
|
|
/** |
|
|
|
|
* Returns whether the more actions button is visible. |
|
|
|
|
* |
|
|
|
|
* @param {Object} state - Global state. |
|
|
|
|
* @param {IState} state - Global state. |
|
|
|
|
* @returns {boolean} |
|
|
|
|
*/ |
|
|
|
|
export const isMoreActionsVisible = (state: Object) => { |
|
|
|
|
export const isMoreActionsVisible = (state: IState) => { |
|
|
|
|
const isLocalModerator = isLocalParticipantModerator(state); |
|
|
|
|
const inBreakoutRoom = isInBreakoutRoom(state); |
|
|
|
|
const { hideMoreActionsButton } = getParticipantsPaneConfig(state); |
|
|
|
@ -293,10 +298,10 @@ export const isMoreActionsVisible = (state: Object) => { |
|
|
|
|
/** |
|
|
|
|
* Returns whether the mute all button is visible. |
|
|
|
|
* |
|
|
|
|
* @param {Object} state - Global state. |
|
|
|
|
* @param {IState} state - Global state. |
|
|
|
|
* @returns {boolean} |
|
|
|
|
*/ |
|
|
|
|
export const isMuteAllVisible = (state: Object) => { |
|
|
|
|
export const isMuteAllVisible = (state: IState) => { |
|
|
|
|
const isLocalModerator = isLocalParticipantModerator(state); |
|
|
|
|
const inBreakoutRoom = isInBreakoutRoom(state); |
|
|
|
|
const { hideMuteAllButton } = getParticipantsPaneConfig(state); |