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.

subscriber.web.js 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // @flow
  2. import { isMobileBrowser } from '../base/environment/utils';
  3. import { getParticipantCountWithFake, pinParticipant } from '../base/participants';
  4. import { StateListenerRegistry } from '../base/redux';
  5. import { clientResized } from '../base/responsive-ui';
  6. import { shouldHideSelfView } from '../base/settings';
  7. import { setFilmstripVisible } from '../filmstrip/actions';
  8. import { selectParticipantInLargeVideo } from '../large-video/actions.any';
  9. import { getParticipantsPaneOpen } from '../participants-pane/functions';
  10. import { setOverflowDrawer } from '../toolbox/actions.web';
  11. import { getCurrentLayout, shouldDisplayTileView, LAYOUTS } from '../video-layout';
  12. import {
  13. setHorizontalViewDimensions,
  14. setStageFilmstripViewDimensions,
  15. setTileViewDimensions,
  16. setVerticalViewDimensions
  17. } from './actions';
  18. import { clearStageParticipants } from './actions.web';
  19. import {
  20. ASPECT_RATIO_BREAKPOINT,
  21. DISPLAY_DRAWER_THRESHOLD
  22. } from './constants';
  23. import {
  24. isFilmstripResizable,
  25. isFilmstripScrollVisible,
  26. updateRemoteParticipants
  27. } from './functions';
  28. import './subscriber.any';
  29. /**
  30. * Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles.
  31. */
  32. StateListenerRegistry.register(
  33. /* selector */ state => {
  34. return {
  35. numberOfParticipants: getParticipantCountWithFake(state),
  36. disableSelfView: shouldHideSelfView(state),
  37. localScreenShare: state['features/base/participants'].localScreenShare
  38. };
  39. },
  40. /* listener */ (currentState, store) => {
  41. const state = store.getState();
  42. const resizableFilmstrip = isFilmstripResizable(state);
  43. if (shouldDisplayTileView(state)) {
  44. store.dispatch(setTileViewDimensions());
  45. }
  46. if (resizableFilmstrip) {
  47. store.dispatch(setVerticalViewDimensions());
  48. }
  49. }, {
  50. deepEquals: true
  51. });
  52. /**
  53. * Listens for changes in the selected layout to calculate the dimensions of the tile view grid and horizontal view.
  54. */
  55. StateListenerRegistry.register(
  56. /* selector */ state => {
  57. return { layout: getCurrentLayout(state),
  58. width: state['features/base/responsive-ui'].clientWidth };
  59. },
  60. /* listener */ ({ layout }, store) => {
  61. switch (layout) {
  62. case LAYOUTS.TILE_VIEW:
  63. store.dispatch(setTileViewDimensions());
  64. break;
  65. case LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW:
  66. store.dispatch(setHorizontalViewDimensions());
  67. break;
  68. case LAYOUTS.VERTICAL_FILMSTRIP_VIEW:
  69. store.dispatch(setVerticalViewDimensions());
  70. if (store.getState()['features/filmstrip'].activeParticipants.length > 1) {
  71. store.dispatch(clearStageParticipants());
  72. }
  73. break;
  74. case LAYOUTS.STAGE_FILMSTRIP_VIEW:
  75. store.dispatch(pinParticipant(null));
  76. break;
  77. }
  78. }, {
  79. deepEquals: true
  80. });
  81. /**
  82. * Listens for changes in the chat state to recompute available width.
  83. */
  84. StateListenerRegistry.register(
  85. /* selector */ state => state['features/chat'].isOpen,
  86. /* listener */ (isChatOpen, store) => {
  87. const { innerWidth, innerHeight } = window;
  88. if (isChatOpen) {
  89. // $FlowFixMe
  90. document.body.classList.add('shift-right');
  91. } else {
  92. // $FlowFixMe
  93. document.body.classList.remove('shift-right');
  94. }
  95. store.dispatch(clientResized(innerWidth, innerHeight));
  96. });
  97. /**
  98. * Listens for changes in the participant pane state to calculate the
  99. * dimensions of the tile view grid and the tiles.
  100. */
  101. StateListenerRegistry.register(
  102. /* selector */ getParticipantsPaneOpen,
  103. /* listener */ (isOpen, store) => {
  104. const { innerWidth, innerHeight } = window;
  105. store.dispatch(clientResized(innerWidth, innerHeight));
  106. });
  107. /**
  108. * Listens for changes in the client width to determine whether the overflow menu(s) should be displayed as drawers.
  109. */
  110. StateListenerRegistry.register(
  111. /* selector */ state => state['features/base/responsive-ui'].clientWidth < DISPLAY_DRAWER_THRESHOLD,
  112. /* listener */ (widthBelowThreshold, store) => {
  113. if (isMobileBrowser()) {
  114. store.dispatch(setOverflowDrawer(widthBelowThreshold));
  115. }
  116. });
  117. /**
  118. * Gracefully hide/show the filmstrip when going past threshold.
  119. */
  120. StateListenerRegistry.register(
  121. /* selector */ state => state['features/base/responsive-ui'].clientWidth < ASPECT_RATIO_BREAKPOINT,
  122. /* listener */ (widthBelowThreshold, store) => {
  123. const state = store.getState();
  124. const { disableFilmstripAutohiding } = state['features/base/config'];
  125. if (!disableFilmstripAutohiding) {
  126. store.dispatch(setFilmstripVisible(!widthBelowThreshold));
  127. }
  128. });
  129. /**
  130. * Listens for changes in the filmstrip width to determine the size of the tiles.
  131. */
  132. StateListenerRegistry.register(
  133. /* selector */ state => state['features/filmstrip'].width?.current,
  134. /* listener */(_, store) => {
  135. store.dispatch(setVerticalViewDimensions());
  136. });
  137. /**
  138. * Listens for changes in the filmstrip config to determine the size of the tiles.
  139. */
  140. StateListenerRegistry.register(
  141. /* selector */ state => state['features/base/config'].filmstrip?.disableResizable,
  142. /* listener */(_, store) => {
  143. store.dispatch(setVerticalViewDimensions());
  144. });
  145. /**
  146. * Listens for changes in the filmstrip scroll visibility.
  147. */
  148. StateListenerRegistry.register(
  149. /* selector */ state => isFilmstripScrollVisible(state),
  150. /* listener */ (_, store) => updateRemoteParticipants(store));
  151. /**
  152. * Listens for changes to determine the size of the stage filmstrip tiles.
  153. */
  154. StateListenerRegistry.register(
  155. /* selector */ state => {
  156. return {
  157. remoteScreenShares: state['features/video-layout'].remoteScreenShares.length,
  158. length: state['features/filmstrip'].activeParticipants.length,
  159. width: state['features/filmstrip'].width?.current,
  160. visible: state['features/filmstrip'].visible,
  161. clientWidth: state['features/base/responsive-ui'].clientWidth,
  162. tileView: state['features/video-layout'].tileViewEnabled
  163. };
  164. },
  165. /* listener */(_, store) => {
  166. if (getCurrentLayout(store.getState()) === LAYOUTS.STAGE_FILMSTRIP_VIEW) {
  167. store.dispatch(setStageFilmstripViewDimensions());
  168. }
  169. }, {
  170. deepEquals: true
  171. });
  172. /**
  173. * Listens for changes in the active participants count determine the stage participant (when
  174. * there's just one).
  175. */
  176. StateListenerRegistry.register(
  177. /* selector */ state => state['features/filmstrip'].activeParticipants.length,
  178. /* listener */(length, store) => {
  179. if (length <= 1) {
  180. store.dispatch(selectParticipantInLargeVideo());
  181. }
  182. });