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.ts 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import { pinParticipant } from '../base/participants/actions';
  2. import { getParticipantCountWithFake } from '../base/participants/functions';
  3. import StateListenerRegistry from '../base/redux/StateListenerRegistry';
  4. import { clientResized, setNarrowLayout } from '../base/responsive-ui/actions';
  5. import { getHideSelfView } from '../base/settings/functions.any';
  6. import { selectParticipantInLargeVideo } from '../large-video/actions.any';
  7. import { getParticipantsPaneOpen } from '../participants-pane/functions';
  8. import { setOverflowDrawer } from '../toolbox/actions.web';
  9. import { LAYOUTS } from '../video-layout/constants';
  10. import { getCurrentLayout, shouldDisplayTileView } from '../video-layout/functions.web';
  11. import { clearStageParticipants,
  12. setFilmstripVisible,
  13. setHorizontalViewDimensions,
  14. setScreenshareFilmstripParticipant,
  15. setScreensharingTileDimensions,
  16. setStageFilmstripViewDimensions,
  17. setTileViewDimensions,
  18. setVerticalViewDimensions
  19. } from './actions.web';
  20. import {
  21. ASPECT_RATIO_BREAKPOINT,
  22. DISPLAY_DRAWER_THRESHOLD
  23. } from './constants';
  24. import {
  25. isFilmstripResizable,
  26. isTopPanelEnabled
  27. } from './functions.web';
  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: getHideSelfView(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. const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
  58. return {
  59. layout: getCurrentLayout(state),
  60. height: clientHeight,
  61. width: clientWidth
  62. };
  63. },
  64. /* listener */ ({ layout }, store) => {
  65. switch (layout) {
  66. case LAYOUTS.TILE_VIEW: {
  67. const { pinnedParticipant } = store.getState()['features/base/participants'];
  68. if (pinnedParticipant) {
  69. store.dispatch(pinParticipant(null));
  70. }
  71. store.dispatch(clearStageParticipants());
  72. store.dispatch(setTileViewDimensions());
  73. break;
  74. }
  75. case LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW:
  76. store.dispatch(setHorizontalViewDimensions());
  77. break;
  78. case LAYOUTS.VERTICAL_FILMSTRIP_VIEW:
  79. store.dispatch(setVerticalViewDimensions());
  80. if (store.getState()['features/filmstrip'].activeParticipants.length > 1) {
  81. store.dispatch(clearStageParticipants());
  82. }
  83. break;
  84. case LAYOUTS.STAGE_FILMSTRIP_VIEW:
  85. store.dispatch(pinParticipant(null));
  86. break;
  87. }
  88. }, {
  89. deepEquals: true
  90. });
  91. /**
  92. * Listens for changes in the chat state to recompute available width.
  93. */
  94. StateListenerRegistry.register(
  95. /* selector */ state => state['features/chat'].isOpen,
  96. /* listener */ (isChatOpen, store) => {
  97. const { innerWidth, innerHeight } = window;
  98. if (isChatOpen) {
  99. document.body.classList.add('shift-right');
  100. } else {
  101. document.body.classList.remove('shift-right');
  102. }
  103. store.dispatch(clientResized(innerWidth, innerHeight));
  104. });
  105. /**
  106. * Listens for changes in the participant pane state to calculate the
  107. * dimensions of the tile view grid and the tiles.
  108. */
  109. StateListenerRegistry.register(
  110. /* selector */ getParticipantsPaneOpen,
  111. /* listener */ (isOpen, store) => {
  112. const { innerWidth, innerHeight } = window;
  113. store.dispatch(clientResized(innerWidth, innerHeight));
  114. });
  115. /**
  116. * Listens for changes in the client width to determine whether the overflow menu(s) should be displayed as drawers.
  117. */
  118. StateListenerRegistry.register(
  119. /* selector */ state => state['features/base/responsive-ui'].clientWidth < DISPLAY_DRAWER_THRESHOLD,
  120. /* listener */ (widthBelowThreshold, store) => {
  121. store.dispatch(setOverflowDrawer(widthBelowThreshold));
  122. store.dispatch(setNarrowLayout(widthBelowThreshold));
  123. });
  124. /**
  125. * Gracefully hide/show the filmstrip when going past threshold.
  126. */
  127. StateListenerRegistry.register(
  128. /* selector */ state => state['features/base/responsive-ui'].clientWidth < ASPECT_RATIO_BREAKPOINT,
  129. /* listener */ (widthBelowThreshold, store) => {
  130. const state = store.getState();
  131. const { disableFilmstripAutohiding } = state['features/base/config'];
  132. if (!disableFilmstripAutohiding) {
  133. store.dispatch(setFilmstripVisible(!widthBelowThreshold));
  134. }
  135. });
  136. /**
  137. * Listens for changes in the filmstrip width to determine the size of the tiles.
  138. */
  139. StateListenerRegistry.register(
  140. /* selector */ state => state['features/filmstrip'].width?.current,
  141. /* listener */(_, store) => {
  142. store.dispatch(setVerticalViewDimensions());
  143. });
  144. /**
  145. * Listens for changes in the filmstrip config to determine the size of the tiles.
  146. */
  147. StateListenerRegistry.register(
  148. /* selector */ state => state['features/base/config'].filmstrip?.disableResizable,
  149. /* listener */(_, store) => {
  150. store.dispatch(setVerticalViewDimensions());
  151. });
  152. /**
  153. * Listens for changes to determine the size of the stage filmstrip tiles.
  154. */
  155. StateListenerRegistry.register(
  156. /* selector */ state => {
  157. return {
  158. remoteScreenShares: state['features/video-layout'].remoteScreenShares.length,
  159. length: state['features/filmstrip'].activeParticipants.length,
  160. width: state['features/filmstrip'].width?.current,
  161. visible: state['features/filmstrip'].visible,
  162. clientWidth: state['features/base/responsive-ui'].clientWidth,
  163. clientHeight: state['features/base/responsive-ui'].clientHeight,
  164. tileView: state['features/video-layout'].tileViewEnabled,
  165. height: state['features/filmstrip'].topPanelHeight?.current
  166. };
  167. },
  168. /* listener */(_, store) => {
  169. if (getCurrentLayout(store.getState()) === LAYOUTS.STAGE_FILMSTRIP_VIEW) {
  170. store.dispatch(setStageFilmstripViewDimensions());
  171. }
  172. }, {
  173. deepEquals: true
  174. });
  175. /**
  176. * Listens for changes in the active participants count determine the stage participant (when
  177. * there's just one).
  178. */
  179. StateListenerRegistry.register(
  180. /* selector */ state => state['features/filmstrip'].activeParticipants,
  181. /* listener */(activeParticipants, store) => {
  182. if (activeParticipants.length <= 1) {
  183. store.dispatch(selectParticipantInLargeVideo());
  184. }
  185. });
  186. /**
  187. * Listens for changes to determine the size of the screenshare filmstrip.
  188. */
  189. StateListenerRegistry.register(
  190. /* selector */ state => {
  191. return {
  192. length: state['features/video-layout'].remoteScreenShares.length,
  193. clientWidth: state['features/base/responsive-ui'].clientWidth,
  194. clientHeight: state['features/base/responsive-ui'].clientHeight,
  195. height: state['features/filmstrip'].topPanelHeight?.current,
  196. width: state['features/filmstrip'].width?.current,
  197. visible: state['features/filmstrip'].visible,
  198. topPanelVisible: state['features/filmstrip'].topPanelVisible
  199. };
  200. },
  201. /* listener */({ length }, store) => {
  202. if (length >= 1 && isTopPanelEnabled(store.getState())) {
  203. store.dispatch(setScreensharingTileDimensions());
  204. }
  205. }, {
  206. deepEquals: true
  207. });
  208. /**
  209. * Listens for changes to clear invalid data.
  210. */
  211. StateListenerRegistry.register(
  212. /* selector */ state => state['features/video-layout'].remoteScreenShares.length,
  213. /* listener */(length, store) => {
  214. if (length === 0) {
  215. store.dispatch(setScreenshareFilmstripParticipant());
  216. }
  217. }, {
  218. deepEquals: true
  219. });