You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

functions.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // @flow
  2. import {
  3. isParticipantApproved,
  4. isEnabledFromState,
  5. isLocalParticipantApprovedFromState
  6. } from '../av-moderation/functions';
  7. import { getFeatureFlag, INVITE_ENABLED } from '../base/flags';
  8. import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
  9. import {
  10. getDominantSpeakerParticipant,
  11. getParticipantCount,
  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 (getParticipantCount(state) > 2 && 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 (participant === dominantSpeaker) {
  69. return MEDIA_STATE.DOMINANT_SPEAKER;
  70. }
  71. if (muted) {
  72. if (isForceMuted(participant, MEDIA_TYPE.AUDIO, state)) {
  73. return MEDIA_STATE.FORCE_MUTED;
  74. }
  75. return MEDIA_STATE.MUTED;
  76. }
  77. return MEDIA_STATE.UNMUTED;
  78. }
  79. /**
  80. * Get a style property from a style declaration as a float.
  81. *
  82. * @param {CSSStyleDeclaration} styles - Style declaration.
  83. * @param {string} name - Property name.
  84. * @returns {number} Float value.
  85. */
  86. export const getFloatStyleProperty = (styles: Object, name: string) =>
  87. parseFloat(styles.getPropertyValue(name));
  88. /**
  89. * Gets the outer height of an element, including margins.
  90. *
  91. * @param {Element} element - Target element.
  92. * @returns {number} Computed height.
  93. */
  94. export const getComputedOuterHeight = (element: HTMLElement) => {
  95. const computedStyle = getComputedStyle(element);
  96. return element.offsetHeight
  97. + getFloatStyleProperty(computedStyle, 'margin-top')
  98. + getFloatStyleProperty(computedStyle, 'margin-bottom');
  99. };
  100. /**
  101. * Returns this feature's root state.
  102. *
  103. * @param {Object} state - Global state.
  104. * @returns {Object} Feature state.
  105. */
  106. const getState = (state: Object) => state[REDUCER_KEY];
  107. /**
  108. * Is the participants pane open.
  109. *
  110. * @param {Object} state - Global state.
  111. * @returns {boolean} Is the participants pane open.
  112. */
  113. export const getParticipantsPaneOpen = (state: Object) => Boolean(getState(state)?.isOpen);
  114. /**
  115. * Returns the type of quick action button to be displayed for a participant.
  116. * The button is displayed when hovering a participant from the participant list.
  117. *
  118. * @param {Object} participant - The participant.
  119. * @param {boolean} isAudioMuted - If audio is muted for the participant.
  120. * @param {Object} state - The redux state.
  121. * @returns {string} - The type of the quick action button.
  122. */
  123. export function getQuickActionButtonType(participant: Object, isAudioMuted: Boolean, state: Object) {
  124. // handled only by moderators
  125. if (isLocalParticipantModerator(state)) {
  126. if (isForceMuted(participant, MEDIA_TYPE.AUDIO, state)) {
  127. return QUICK_ACTION_BUTTON.ASK_TO_UNMUTE;
  128. }
  129. if (!isAudioMuted) {
  130. return QUICK_ACTION_BUTTON.MUTE;
  131. }
  132. }
  133. return QUICK_ACTION_BUTTON.NONE;
  134. }
  135. /**
  136. * Returns true if the invite button should be rendered.
  137. *
  138. * @param {Object} state - Global state.
  139. * @returns {boolean}
  140. */
  141. export const shouldRenderInviteButton = (state: Object) => {
  142. const { disableInviteFunctions } = toState(state)['features/base/config'];
  143. const flagEnabled = getFeatureFlag(state, INVITE_ENABLED, true);
  144. return flagEnabled && !disableInviteFunctions;
  145. };