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 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // @flow
  2. import Filmstrip from '../../../modules/UI/videolayout/Filmstrip';
  3. import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
  4. import { StateListenerRegistry, equals } from '../base/redux';
  5. import { setFilmstripVisible } from '../filmstrip/actions';
  6. import { setOverflowDrawer } from '../toolbox/actions.web';
  7. import { getCurrentLayout, getTileViewGridDimensions, shouldDisplayTileView, LAYOUTS } from '../video-layout';
  8. import { setHorizontalViewDimensions, setTileViewDimensions } from './actions.web';
  9. import {
  10. ASPECT_RATIO_BREAKPOINT,
  11. DISPLAY_DRAWER_THRESHOLD,
  12. SINGLE_COLUMN_BREAKPOINT,
  13. TWO_COLUMN_BREAKPOINT
  14. } from './constants';
  15. /**
  16. * Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles.
  17. */
  18. StateListenerRegistry.register(
  19. /* selector */ state => state['features/base/participants'].length,
  20. /* listener */ (numberOfParticipants, store) => {
  21. const state = store.getState();
  22. if (shouldDisplayTileView(state)) {
  23. const gridDimensions = getTileViewGridDimensions(state);
  24. const oldGridDimensions = state['features/filmstrip'].tileViewDimensions.gridDimensions;
  25. if (!equals(gridDimensions, oldGridDimensions)) {
  26. const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
  27. const { isOpen } = state['features/chat'];
  28. store.dispatch(
  29. setTileViewDimensions(
  30. gridDimensions,
  31. {
  32. clientHeight,
  33. clientWidth
  34. },
  35. isOpen
  36. )
  37. );
  38. }
  39. }
  40. });
  41. /**
  42. * Listens for changes in the selected layout to calculate the dimensions of the tile view grid and horizontal view.
  43. */
  44. StateListenerRegistry.register(
  45. /* selector */ state => getCurrentLayout(state),
  46. /* listener */ (layout, store) => {
  47. const state = store.getState();
  48. switch (layout) {
  49. case LAYOUTS.TILE_VIEW: {
  50. const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
  51. const { isOpen } = state['features/chat'];
  52. store.dispatch(
  53. setTileViewDimensions(
  54. getTileViewGridDimensions(state),
  55. {
  56. clientHeight,
  57. clientWidth
  58. },
  59. isOpen
  60. )
  61. );
  62. break;
  63. }
  64. case LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW:
  65. store.dispatch(setHorizontalViewDimensions(state['features/base/responsive-ui'].clientHeight));
  66. break;
  67. case LAYOUTS.VERTICAL_FILMSTRIP_VIEW:
  68. // Once the thumbnails are reactified this should be moved there too.
  69. Filmstrip.resizeThumbnailsForVerticalView();
  70. break;
  71. }
  72. });
  73. /**
  74. * Handles on stage participant updates.
  75. */
  76. StateListenerRegistry.register(
  77. /* selector */ state => state['features/large-video'].participantId,
  78. /* listener */ (participantId, store, oldParticipantId) => {
  79. const newThumbnail = VideoLayout.getSmallVideo(participantId);
  80. const oldThumbnail = VideoLayout.getSmallVideo(oldParticipantId);
  81. if (newThumbnail) {
  82. newThumbnail.updateView();
  83. }
  84. if (oldThumbnail) {
  85. oldThumbnail.updateView();
  86. }
  87. }
  88. );
  89. /**
  90. * Listens for changes in the chat state to calculate the dimensions of the tile view grid and the tiles.
  91. */
  92. StateListenerRegistry.register(
  93. /* selector */ state => state['features/chat'].isOpen,
  94. /* listener */ (isChatOpen, store) => {
  95. const state = store.getState();
  96. if (isChatOpen) {
  97. // $FlowFixMe
  98. document.body.classList.add('shift-right');
  99. } else {
  100. // $FlowFixMe
  101. document.body.classList.remove('shift-right');
  102. }
  103. if (shouldDisplayTileView(state)) {
  104. const gridDimensions = getTileViewGridDimensions(state);
  105. const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
  106. store.dispatch(
  107. setTileViewDimensions(
  108. gridDimensions,
  109. {
  110. clientHeight,
  111. clientWidth
  112. },
  113. isChatOpen
  114. )
  115. );
  116. }
  117. });
  118. /**
  119. * Listens for changes in the client width to determine whether the overflow menu(s) should be displayed as drawers.
  120. */
  121. StateListenerRegistry.register(
  122. /* selector */ state => state['features/base/responsive-ui'].clientWidth < DISPLAY_DRAWER_THRESHOLD,
  123. /* listener */ (widthBelowThreshold, store) => {
  124. store.dispatch(setOverflowDrawer(widthBelowThreshold));
  125. });
  126. /**
  127. * Gracefully hide/show the filmstrip when going past threshold.
  128. */
  129. StateListenerRegistry.register(
  130. /* selector */ state => state['features/base/responsive-ui'].clientWidth < ASPECT_RATIO_BREAKPOINT,
  131. /* listener */ (widthBelowThreshold, store) => {
  132. store.dispatch(setFilmstripVisible(!widthBelowThreshold));
  133. });
  134. /**
  135. * Symbol mapping used for the tile view responsiveness computation.
  136. */
  137. const responsiveColumnMapping = {
  138. singleColumn: Symbol('singleColumn'),
  139. twoColumns: Symbol('twoColumns'),
  140. twoParticipantsSingleColumn: Symbol('twoParticipantsSingleColumn')
  141. };
  142. /**
  143. * Listens for changes in the screen size to recompute
  144. * the dimensions of the tile view grid and the tiles for responsiveness.
  145. */
  146. StateListenerRegistry.register(
  147. /* selector */ state => {
  148. const { clientWidth } = state['features/base/responsive-ui'];
  149. if (clientWidth < TWO_COLUMN_BREAKPOINT && clientWidth >= ASPECT_RATIO_BREAKPOINT) {
  150. // Forcing the recomputation of tiles when screen switches in or out of
  151. // the (TWO_COLUMN_BREAKPOINT, ASPECT_RATIO_BREAKPOINT] interval.
  152. return responsiveColumnMapping.twoColumns;
  153. } else if (clientWidth < ASPECT_RATIO_BREAKPOINT && clientWidth >= SINGLE_COLUMN_BREAKPOINT) {
  154. // Forcing the recomputation of tiles when screen switches in or out of
  155. // the (ASPECT_RATIO_BREAKPOINT, SINGLE_COLUMN_BREAKPOINT] interval.
  156. return responsiveColumnMapping.twoParticipantsSingleColumn;
  157. }
  158. /**
  159. * This gets called either when the width of the screen is above {@code TWO_COLUMN_BREAKPOINT}
  160. * or below {@CODE SINGLE_COLUMN_BREAKPOINT}, however, the internal logic from {@code getMaxColumnCount}
  161. * only takes the second case into consideration.
  162. */
  163. return responsiveColumnMapping.singleColumn;
  164. },
  165. /* listener */ (_, store) => {
  166. const state = store.getState();
  167. if (shouldDisplayTileView(state)) {
  168. const gridDimensions = getTileViewGridDimensions(state);
  169. const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
  170. const { isOpen } = state['features/chat'];
  171. store.dispatch(
  172. setTileViewDimensions(
  173. gridDimensions,
  174. {
  175. clientHeight,
  176. clientWidth
  177. },
  178. isOpen
  179. )
  180. );
  181. }
  182. });