Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

functions.js 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // @flow
  2. import {
  3. isParticipantApproved,
  4. isEnabledFromState,
  5. isLocalParticipantApprovedFromState,
  6. isSupported
  7. } from '../av-moderation/functions';
  8. import { getFeatureFlag, INVITE_ENABLED } from '../base/flags';
  9. import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
  10. import {
  11. getDominantSpeakerParticipant,
  12. isLocalParticipantModerator,
  13. isParticipantModerator
  14. } from '../base/participants/functions';
  15. import { toState } from '../base/redux';
  16. import { QUICK_ACTION_BUTTON, REDUCER_KEY, MEDIA_STATE } from './constants';
  17. /**
  18. * Generates a class attribute value.
  19. *
  20. * @param {Iterable<string>} args - String iterable.
  21. * @returns {string} Class attribute value.
  22. */
  23. export const classList = (...args: Array<string | boolean>) => args.filter(Boolean).join(' ');
  24. /**
  25. * Find the first styled ancestor component of an element.
  26. *
  27. * @param {Element} target - Element to look up.
  28. * @param {StyledComponentClass} component - Styled component reference.
  29. * @returns {Element|null} Ancestor.
  30. */
  31. export const findStyledAncestor = (target: Object, component: any) => {
  32. if (!target || target.matches(`.${component.styledComponentId}`)) {
  33. return target;
  34. }
  35. return findStyledAncestor(target.parentElement, component);
  36. };
  37. /**
  38. * Checks if a participant is force muted.
  39. *
  40. * @param {Object} participant - The participant.
  41. * @param {MediaType} mediaType - The media type.
  42. * @param {Object} state - The redux state.
  43. * @returns {MediaState}
  44. */
  45. export function isForceMuted(participant: Object, mediaType: MediaType, state: Object) {
  46. if (isEnabledFromState(mediaType, state)) {
  47. if (participant.local) {
  48. return !isLocalParticipantApprovedFromState(mediaType, state);
  49. }
  50. // moderators cannot be force muted
  51. if (isParticipantModerator(participant)) {
  52. return false;
  53. }
  54. return !isParticipantApproved(participant.id, mediaType)(state);
  55. }
  56. return false;
  57. }
  58. /**
  59. * Determines the audio media state (the mic icon) for a participant.
  60. *
  61. * @param {Object} participant - The participant.
  62. * @param {boolean} muted - The mute state of the participant.
  63. * @param {Object} state - The redux state.
  64. * @returns {MediaState}
  65. */
  66. export function getParticipantAudioMediaState(participant: Object, muted: Boolean, state: Object) {
  67. const dominantSpeaker = getDominantSpeakerParticipant(state);
  68. if (muted) {
  69. if (isForceMuted(participant, MEDIA_TYPE.AUDIO, state)) {
  70. return MEDIA_STATE.FORCE_MUTED;
  71. }
  72. return MEDIA_STATE.MUTED;
  73. }
  74. if (participant === dominantSpeaker) {
  75. return MEDIA_STATE.DOMINANT_SPEAKER;
  76. }
  77. return MEDIA_STATE.UNMUTED;
  78. }
  79. /**
  80. * Determines the video media state (the mic icon) for a participant.
  81. *
  82. * @param {Object} participant - The participant.
  83. * @param {boolean} muted - The mute state of the participant.
  84. * @param {Object} state - The redux state.
  85. * @returns {MediaState}
  86. */
  87. export function getParticipantVideoMediaState(participant: Object, muted: Boolean, state: Object) {
  88. if (muted) {
  89. if (isForceMuted(participant, MEDIA_TYPE.VIDEO, state)) {
  90. return MEDIA_STATE.FORCE_MUTED;
  91. }
  92. return MEDIA_STATE.MUTED;
  93. }
  94. return MEDIA_STATE.UNMUTED;
  95. }
  96. /**
  97. * Get a style property from a style declaration as a float.
  98. *
  99. * @param {CSSStyleDeclaration} styles - Style declaration.
  100. * @param {string} name - Property name.
  101. * @returns {number} Float value.
  102. */
  103. export const getFloatStyleProperty = (styles: Object, name: string) =>
  104. parseFloat(styles.getPropertyValue(name));
  105. /**
  106. * Gets the outer height of an element, including margins.
  107. *
  108. * @param {Element} element - Target element.
  109. * @returns {number} Computed height.
  110. */
  111. export const getComputedOuterHeight = (element: HTMLElement) => {
  112. const computedStyle = getComputedStyle(element);
  113. return element.offsetHeight
  114. + getFloatStyleProperty(computedStyle, 'margin-top')
  115. + getFloatStyleProperty(computedStyle, 'margin-bottom');
  116. };
  117. /**
  118. * Returns this feature's root state.
  119. *
  120. * @param {Object} state - Global state.
  121. * @returns {Object} Feature state.
  122. */
  123. const getState = (state: Object) => state[REDUCER_KEY];
  124. /**
  125. * Is the participants pane open.
  126. *
  127. * @param {Object} state - Global state.
  128. * @returns {boolean} Is the participants pane open.
  129. */
  130. export const getParticipantsPaneOpen = (state: Object) => Boolean(getState(state)?.isOpen);
  131. /**
  132. * Returns the type of quick action button to be displayed for a participant.
  133. * The button is displayed when hovering a participant from the participant list.
  134. *
  135. * @param {Object} participant - The participant.
  136. * @param {boolean} isAudioMuted - If audio is muted for the participant.
  137. * @param {Object} state - The redux state.
  138. * @returns {string} - The type of the quick action button.
  139. */
  140. export function getQuickActionButtonType(participant: Object, isAudioMuted: Boolean, state: Object) {
  141. // handled only by moderators
  142. if (isLocalParticipantModerator(state)) {
  143. if (!isAudioMuted) {
  144. return QUICK_ACTION_BUTTON.MUTE;
  145. }
  146. if (isSupported()(state)) {
  147. return QUICK_ACTION_BUTTON.ASK_TO_UNMUTE;
  148. }
  149. }
  150. return QUICK_ACTION_BUTTON.NONE;
  151. }
  152. /**
  153. * Returns true if the invite button should be rendered.
  154. *
  155. * @param {Object} state - Global state.
  156. * @returns {boolean}
  157. */
  158. export const shouldRenderInviteButton = (state: Object) => {
  159. const { disableInviteFunctions } = toState(state)['features/base/config'];
  160. const flagEnabled = getFeatureFlag(state, INVITE_ENABLED, true);
  161. return flagEnabled && !disableInviteFunctions;
  162. };