@100mslive/roomkit-react 0.3.8-alpha.0 → 0.3.8-alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/dist/{HLSView-CTZXD762.js → HLSView-XZDT3RRC.js} +2 -2
  2. package/dist/Prebuilt/common/constants.d.ts +2 -0
  3. package/dist/Prebuilt/common/hooks.d.ts +10 -0
  4. package/dist/Prebuilt/components/CaptionIcon.d.ts +2 -0
  5. package/dist/Prebuilt/components/FullPageProgress.d.ts +8 -0
  6. package/dist/Prebuilt/components/VirtualBackground/VBHandler.d.ts +3 -3
  7. package/dist/Prebuilt/plugins/CaptionsViewer.d.ts +2 -0
  8. package/dist/Text/Text.d.ts +1 -1
  9. package/dist/{chunk-NDLMRKFR.js → chunk-SQPIZNW2.js} +2367 -2128
  10. package/dist/chunk-SQPIZNW2.js.map +7 -0
  11. package/dist/index.cjs.js +3254 -2998
  12. package/dist/index.cjs.js.map +4 -4
  13. package/dist/index.js +1 -1
  14. package/dist/meta.cjs.json +244 -86
  15. package/dist/meta.esbuild.json +250 -92
  16. package/package.json +6 -6
  17. package/src/Prebuilt/common/constants.ts +2 -0
  18. package/src/Prebuilt/common/hooks.ts +72 -1
  19. package/src/Prebuilt/components/AppData/AppData.tsx +2 -0
  20. package/src/Prebuilt/components/AppData/useUISettings.js +10 -0
  21. package/src/Prebuilt/components/CaptionIcon.tsx +27 -0
  22. package/src/Prebuilt/components/ConferenceScreen.tsx +34 -4
  23. package/src/Prebuilt/components/Footer/Footer.tsx +2 -0
  24. package/src/Prebuilt/components/Footer/RoleAccordion.tsx +1 -1
  25. package/src/Prebuilt/components/{FullPageProgress.jsx → FullPageProgress.tsx} +10 -1
  26. package/src/Prebuilt/components/Header/StreamActions.tsx +3 -25
  27. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +25 -26
  28. package/src/Prebuilt/components/Notifications/PeerNotifications.tsx +1 -11
  29. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +4 -9
  30. package/src/Prebuilt/components/Preview/PreviewScreen.tsx +0 -3
  31. package/src/Prebuilt/components/Settings/StartRecording.jsx +4 -37
  32. package/src/Prebuilt/components/Toast/ToastConfig.jsx +0 -22
  33. package/src/Prebuilt/components/VirtualBackground/VBHandler.tsx +3 -3
  34. package/src/Prebuilt/components/VirtualBackground/VBOption.tsx +3 -1
  35. package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +23 -7
  36. package/src/Prebuilt/components/VirtualBackground/VBToggle.tsx +5 -3
  37. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +0 -3
  38. package/src/Prebuilt/plugins/CaptionsViewer.tsx +191 -0
  39. package/dist/chunk-NDLMRKFR.js.map +0 -7
  40. /package/dist/{HLSView-CTZXD762.js.map → HLSView-XZDT3RRC.js.map} +0 -0
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.3.8-alpha.0",
13
+ "version": "0.3.8-alpha.2",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -82,11 +82,11 @@
82
82
  "react": ">=17.0.2 <19.0.0"
83
83
  },
84
84
  "dependencies": {
85
- "@100mslive/hls-player": "0.3.8-alpha.0",
85
+ "@100mslive/hls-player": "0.3.8-alpha.2",
86
86
  "@100mslive/hms-noise-cancellation": "0.0.1",
87
- "@100mslive/hms-virtual-background": "1.13.8-alpha.0",
88
- "@100mslive/react-icons": "0.10.8-alpha.0",
89
- "@100mslive/react-sdk": "0.10.8-alpha.0",
87
+ "@100mslive/hms-virtual-background": "1.13.8-alpha.2",
88
+ "@100mslive/react-icons": "0.10.8-alpha.2",
89
+ "@100mslive/react-sdk": "0.10.8-alpha.2",
90
90
  "@100mslive/types-prebuilt": "0.12.8",
91
91
  "@emoji-mart/data": "^1.0.6",
92
92
  "@emoji-mart/react": "^1.0.1",
@@ -122,5 +122,5 @@
122
122
  "uuid": "^8.3.2",
123
123
  "worker-timers": "^7.0.40"
124
124
  },
125
- "gitHead": "01f2b5f23cc814beb7f077b46b6736f1e00ceaad"
125
+ "gitHead": "43ee35cc85faabb5a827f7f41a5affebffcfca18"
126
126
  }
@@ -47,6 +47,8 @@ export const APP_DATA = {
47
47
  pollState: 'pollState',
48
48
  background: 'background',
49
49
  sheet: 'sheet',
50
+ caption: 'caption',
51
+ loadingEffects: 'loadingEffects',
50
52
  };
51
53
 
52
54
  export const UI_SETTINGS = {
@@ -3,20 +3,27 @@ import { useMedia } from 'react-use';
3
3
  import { HMSHLSPlayer } from '@100mslive/hls-player';
4
4
  import { JoinForm_JoinBtnType } from '@100mslive/types-prebuilt/elements/join_form';
5
5
  import {
6
+ HMSRecording,
6
7
  parsedUserAgent,
7
8
  selectAvailableRoleNames,
8
9
  selectIsConnectedToRoom,
9
10
  selectPeerCount,
10
11
  selectPeerMetadata,
11
12
  selectPeers,
13
+ selectRecordingState,
12
14
  selectRemotePeers,
15
+ useHMSActions,
13
16
  useHMSStore,
14
17
  useHMSVanillaStore,
15
18
  } from '@100mslive/react-sdk';
19
+ // @ts-ignore: No implicit any
20
+ import { ToastManager } from '../components/Toast/ToastManager';
16
21
  import { config } from '../../Theme';
17
22
  import { useRoomLayout } from '../provider/roomLayoutProvider';
23
+ // @ts-ignore
24
+ import { useSetAppDataByKey } from '../components/AppData/useUISettings';
18
25
  import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
19
- import { CHAT_SELECTOR } from './constants';
26
+ import { APP_DATA, CHAT_SELECTOR, RTMP_RECORD_DEFAULT_RESOLUTION } from './constants';
20
27
  /**
21
28
  * Hook to execute a callback when alone in room(after a certain 5d of time)
22
29
  * @param {number} thresholdMs The threshold(in ms) after which the callback is executed,
@@ -147,3 +154,67 @@ export const useKeyboardHandler = (isPaused: boolean, hlsPlayer: HMSHLSPlayer) =
147
154
 
148
155
  return handleKeyEvent;
149
156
  };
157
+ export interface RTMPRecordingResolution {
158
+ width: number;
159
+ height: number;
160
+ }
161
+ export const useRecordingHandler = () => {
162
+ const hmsActions = useHMSActions();
163
+ const recordingState: HMSRecording = useHMSStore(selectRecordingState);
164
+ const [isRecordingLoading, setIsRecordingLoading] = useState(false);
165
+ const [recordingStarted, setRecordingState] = useSetAppDataByKey(APP_DATA.recordingStarted);
166
+ useEffect(() => {
167
+ if (recordingState.browser.error && recordingStarted) {
168
+ setRecordingState(false);
169
+ }
170
+ }, [recordingStarted, recordingState.browser.error, setRecordingState]);
171
+ const startRecording = useCallback(
172
+ async (resolution: RTMPRecordingResolution | null = null) => {
173
+ try {
174
+ setRecordingState(true);
175
+ setIsRecordingLoading(true);
176
+ await hmsActions.startRTMPOrRecording({
177
+ resolution: getResolution(resolution),
178
+ record: true,
179
+ });
180
+ } catch (error) {
181
+ const err = error as Error;
182
+ if (err.message.includes('stream already running')) {
183
+ ToastManager.addToast({
184
+ title: 'Recording already running',
185
+ variant: 'error',
186
+ });
187
+ } else {
188
+ ToastManager.addToast({
189
+ title: err.message,
190
+ variant: 'error',
191
+ });
192
+ }
193
+ setRecordingState(false);
194
+ }
195
+ setIsRecordingLoading(false);
196
+ },
197
+ [hmsActions, setRecordingState],
198
+ );
199
+ return {
200
+ recordingStarted,
201
+ startRecording,
202
+ isRecordingLoading,
203
+ };
204
+ };
205
+
206
+ export function getResolution(
207
+ recordingResolution: RTMPRecordingResolution | null,
208
+ ): RTMPRecordingResolution | undefined {
209
+ if (!recordingResolution) {
210
+ return undefined;
211
+ }
212
+ const resolution: RTMPRecordingResolution = RTMP_RECORD_DEFAULT_RESOLUTION;
213
+ if (recordingResolution.width) {
214
+ resolution.width = recordingResolution.width;
215
+ }
216
+ if (recordingResolution.height) {
217
+ resolution.height = recordingResolution.height;
218
+ }
219
+ return resolution;
220
+ }
@@ -62,11 +62,13 @@ const initialAppData = {
62
62
  [APP_DATA.minimiseInset]: false,
63
63
  [APP_DATA.activeScreensharePeerId]: '',
64
64
  [APP_DATA.disableNotifications]: false,
65
+ [APP_DATA.loadingEffects]: false,
65
66
  [APP_DATA.background]: 'none',
66
67
  [APP_DATA.pollState]: {
67
68
  [POLL_STATE.pollInView]: '',
68
69
  [POLL_STATE.view]: '',
69
70
  },
71
+ [APP_DATA.caption]: true,
70
72
  };
71
73
 
72
74
  export const AppData = React.memo(() => {
@@ -107,6 +107,16 @@ export const useSetSubscribedNotifications = notificationKey => {
107
107
  return [value, setValue];
108
108
  };
109
109
 
110
+ export const useIsCaptionEnabled = () => {
111
+ const isCaptionEnabled = useHMSStore(selectAppDataByPath(APP_DATA.caption));
112
+ return isCaptionEnabled;
113
+ };
114
+
115
+ export const useSetIsCaptionEnabled = () => {
116
+ const [value, setValue] = useSetAppDataByKey(APP_DATA.caption);
117
+ return [value, setValue];
118
+ };
119
+
110
120
  export const useSubscribeChatSelector = chatSelectorKey => {
111
121
  const chatSelectorPreference = useHMSStore(selectAppDataByPath(APP_DATA.chatSelector, chatSelectorKey));
112
122
  return chatSelectorPreference;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { selectIsTranscriptionEnabled, useHMSStore } from '@100mslive/react-sdk';
3
+ import { ClosedCaptionIcon, OpenCaptionIcon } from '@100mslive/react-icons';
4
+ import { Tooltip } from '../../Tooltip';
5
+ // @ts-ignore: No implicit Any
6
+ import IconButton from '../IconButton';
7
+ // @ts-ignore: No implicit Any
8
+ import { useSetIsCaptionEnabled } from './AppData/useUISettings.js';
9
+
10
+ export const CaptionIcon = () => {
11
+ const isCaptionPresent = useHMSStore(selectIsTranscriptionEnabled);
12
+ const [isCaption, setIsCaption] = useSetIsCaptionEnabled();
13
+
14
+ const onClick = () => {
15
+ setIsCaption(!isCaption);
16
+ };
17
+ if (!isCaptionPresent) {
18
+ return null;
19
+ }
20
+ return (
21
+ <Tooltip title={isCaption ? 'Disable caption' : 'Enable caption'}>
22
+ <IconButton data-testid="caption_btn" onClick={onClick}>
23
+ {isCaption ? <ClosedCaptionIcon width="20" height="20px" /> : <OpenCaptionIcon width="20" height="20px" />}
24
+ </IconButton>
25
+ </Tooltip>
26
+ );
27
+ };
@@ -1,4 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
+ import { useMedia } from 'react-use';
2
3
  import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
3
4
  import { v4 as uuid } from 'uuid';
4
5
  import {
@@ -18,27 +19,30 @@ import { ActivatedPIP } from './PIP/PIPComponent';
18
19
  import { PictureInPicture } from './PIP/PIPManager';
19
20
  import { RoleChangeRequestModal } from './RoleChangeRequest/RoleChangeRequestModal';
20
21
  import { Box, Flex } from '../../Layout';
22
+ import { config } from '../../Theme';
21
23
  import { useHMSPrebuiltContext } from '../AppContext';
22
24
  import { VideoStreamingSection } from '../layouts/VideoStreamingSection';
23
25
  // @ts-ignore: No implicit Any
24
26
  import { EmojiReaction } from './EmojiReaction';
25
- // @ts-ignore: No implicit Any
26
27
  import FullPageProgress from './FullPageProgress';
27
28
  import { Header } from './Header';
28
29
  import { PreviousRoleInMetadata } from './PreviousRoleInMetadata';
29
30
  import { RaiseHand } from './RaiseHand';
31
+ import { CaptionsViewer } from '../plugins/CaptionsViewer';
30
32
  import {
31
33
  useRoomLayoutConferencingScreen,
32
34
  useRoomLayoutPreviewScreen,
33
35
  } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
34
36
  // @ts-ignore: No implicit Any
35
- import { useAuthToken, useSetAppDataByKey } from './AppData/useUISettings';
36
- import { useLandscapeHLSStream, useMobileHLSStream } from '../common/hooks';
37
+ import { useIsSidepaneTypeOpen } from './AppData/useSidepane';
37
38
  // @ts-ignore: No implicit Any
38
- import { APP_DATA, isAndroid, isIOS, isIPadOS } from '../common/constants';
39
+ import { useAuthToken, useIsCaptionEnabled, useSetAppDataByKey } from './AppData/useUISettings';
40
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../common/hooks';
41
+ import { APP_DATA, isAndroid, isIOS, isIPadOS, SIDE_PANE_OPTIONS } from '../common/constants';
39
42
 
40
43
  export const ConferenceScreen = () => {
41
44
  const { userName, endpoints, onJoin: onJoinFunc } = useHMSPrebuiltContext();
45
+ const isMobile = useMedia(config.media.md);
42
46
  const screenProps = useRoomLayoutConferencingScreen();
43
47
  const { isPreviewScreenEnabled } = useRoomLayoutPreviewScreen();
44
48
  const roomState = useHMSStore(selectRoomState);
@@ -59,6 +63,10 @@ export const ConferenceScreen = () => {
59
63
  const isMobileHLSStream = useMobileHLSStream();
60
64
  const isLandscapeHLSStream = useLandscapeHLSStream();
61
65
  const isMwebHLSStream = isMobileHLSStream || isLandscapeHLSStream;
66
+ const isCaptionEnabled = useIsCaptionEnabled();
67
+ const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT);
68
+
69
+ const showCaptionAtTop = screenProps.elements?.chat?.is_overlay && isChatOpen;
62
70
 
63
71
  const toggleControls = () => {
64
72
  if (dropdownListRef.current?.length === 0 && isMobileDevice && !isMwebHLSStream) {
@@ -126,6 +134,28 @@ export const ConferenceScreen = () => {
126
134
  <FullPageProgress text="Starting live stream..." css={{ opacity: 0.8, bg: '$background_dim' }} />
127
135
  </Box>
128
136
  ) : null}
137
+ {isCaptionEnabled && screenProps.screenType !== 'hls_live_streaming' && (
138
+ <Box
139
+ css={{
140
+ position: 'fixed',
141
+ maxWidth: isMobile ? '100%' : '40%',
142
+ bottom: showCaptionAtTop ? '' : hideControlsForStreaming ? '5%' : '10%',
143
+ top: showCaptionAtTop ? (hideControlsForStreaming ? '5%' : '10%') : '',
144
+ left: isMobile ? 0 : '50%',
145
+ transform: isMobile ? '' : 'translateX(-50%)',
146
+ background: '#000000A3',
147
+ overflow: 'clip',
148
+ zIndex: 10,
149
+ height: 'fit-content',
150
+ r: '$1',
151
+ p: '$6',
152
+ transition: 'bottom 0.3s ease-in-out',
153
+ '&:empty': { display: 'none' },
154
+ }}
155
+ >
156
+ <CaptionsViewer />
157
+ </Box>
158
+ )}
129
159
  <Flex css={{ size: '100%', overflow: 'hidden' }} direction="column">
130
160
  {!(screenProps.hideSections.includes('header') || isMwebHLSStream) && (
131
161
  <Box
@@ -5,6 +5,7 @@ import { Chat_ChatState } from '@100mslive/types-prebuilt/elements/chat';
5
5
  import { config as cssConfig, Footer as AppFooter } from '../../..';
6
6
  // @ts-ignore: No implicit Any
7
7
  import { AudioVideoToggle } from '../AudioVideoToggle';
8
+ import { CaptionIcon } from '../CaptionIcon';
8
9
  // @ts-ignore: No implicit Any
9
10
  import { EmojiReaction } from '../EmojiReaction';
10
11
  // @ts-ignore: No implicit Any
@@ -96,6 +97,7 @@ export const Footer = ({
96
97
  <>
97
98
  <ScreenshareToggle />
98
99
  <RaiseHand />
100
+ {screenType !== 'hls_live_streaming' && <CaptionIcon />}
99
101
  {elements?.emoji_reactions && <EmojiReaction />}
100
102
  <LeaveRoom screenType={screenType} />
101
103
  </>
@@ -109,7 +109,7 @@ export const RoleAccordion = ({
109
109
  },
110
110
  }}
111
111
  >
112
- <Flex justify="between" css={{ flexGrow: 1, pr: '$6' }}>
112
+ <Flex justify="between" align="center" css={{ flexGrow: 1, pr: '$6' }}>
113
113
  <Text
114
114
  variant="sm"
115
115
  css={{ fontWeight: '$semiBold', textTransform: 'capitalize', color: '$on_surface_medium' }}
@@ -2,8 +2,17 @@ import React from 'react';
2
2
  import { Flex } from '../../Layout';
3
3
  import { Loading } from '../../Loading';
4
4
  import { Text } from '../../Text';
5
+ import { CSS } from '../../Theme';
5
6
 
6
- const FullPageProgress = ({ loaderColor = '$primary_default', text = '', css = {} }) => (
7
+ const FullPageProgress = ({
8
+ loaderColor = '$primary_default',
9
+ text = '',
10
+ css = {},
11
+ }: {
12
+ loaderColor?: string;
13
+ text?: string;
14
+ css?: CSS;
15
+ }) => (
7
16
  <Flex direction="column" justify="center" align="center" css={{ size: '100%', color: loaderColor, ...css }}>
8
17
  <Loading color="currentColor" size={100} />
9
18
  {text ? <Text css={{ mt: '$10', color: '$on_surface_high' }}>{text}</Text> : null}
@@ -20,12 +20,9 @@ import { ToastManager } from '../Toast/ToastManager';
20
20
  // @ts-ignore
21
21
  import { AdditionalRoomState, getRecordingText } from './AdditionalRoomState';
22
22
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
23
- // @ts-ignore
24
- import { useSetAppDataByKey } from '../AppData/useUISettings';
23
+ import { useRecordingHandler } from '../../common/hooks';
25
24
  // @ts-ignore
26
25
  import { formatTime } from '../../common/utils';
27
- // @ts-ignore
28
- import { APP_DATA } from '../../common/constants';
29
26
 
30
27
  export const LiveStatus = () => {
31
28
  const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
@@ -147,7 +144,7 @@ export const RecordingPauseStatus = () => {
147
144
  const StartRecording = () => {
148
145
  const permissions = useHMSStore(selectPermissions);
149
146
  const [open, setOpen] = useState(false);
150
- const [recordingStarted, setRecordingState] = useSetAppDataByKey(APP_DATA.recordingStarted);
147
+ const { startRecording, recordingStarted } = useRecordingHandler();
151
148
  const { isBrowserRecordingOn, isStreamingOn, isHLSRunning } = useRecordingStreaming();
152
149
  const hmsActions = useHMSActions();
153
150
  if (!permissions?.browserRecording || isHLSRunning) {
@@ -201,26 +198,7 @@ const StartRecording = () => {
201
198
  icon
202
199
  disabled={recordingStarted || isStreamingOn}
203
200
  onClick={async () => {
204
- try {
205
- setRecordingState(true);
206
- await hmsActions.startRTMPOrRecording({
207
- record: true,
208
- });
209
- } catch (error) {
210
- const err = error as Error;
211
- if (err.message.includes('stream already running')) {
212
- ToastManager.addToast({
213
- title: 'Recording already running',
214
- variant: 'error',
215
- });
216
- } else {
217
- ToastManager.addToast({
218
- title: err.message,
219
- variant: 'error',
220
- });
221
- }
222
- setRecordingState(false);
223
- }
201
+ await startRecording();
224
202
  }}
225
203
  >
226
204
  {recordingStarted ? <Loading size={24} color="currentColor" /> : <RecordIcon />}
@@ -5,6 +5,7 @@ import { match } from 'ts-pattern';
5
5
  import {
6
6
  selectIsConnectedToRoom,
7
7
  selectIsLocalVideoEnabled,
8
+ selectIsTranscriptionEnabled,
8
9
  selectPeerCount,
9
10
  selectPermissions,
10
11
  useHMSActions,
@@ -13,12 +14,14 @@ import {
13
14
  } from '@100mslive/react-sdk';
14
15
  import {
15
16
  BrbIcon,
17
+ ClosedCaptionIcon,
16
18
  CrossIcon,
17
19
  EmojiIcon,
18
20
  HamburgerMenuIcon,
19
21
  HandIcon,
20
22
  HandRaiseSlashedIcon,
21
23
  InfoIcon,
24
+ OpenCaptionIcon,
22
25
  PeopleIcon,
23
26
  QuizActiveIcon,
24
27
  QuizIcon,
@@ -49,12 +52,12 @@ import { useSheetToggle } from '../../AppData/useSheet';
49
52
  // @ts-ignore: No implicit any
50
53
  import { usePollViewToggle, useSidepaneToggle } from '../../AppData/useSidepane';
51
54
  // @ts-ignore: No implicit Any
52
- import { useShowPolls } from '../../AppData/useUISettings';
55
+ import { useSetIsCaptionEnabled, useShowPolls } from '../../AppData/useUISettings';
53
56
  // @ts-ignore: No implicit any
54
57
  import { useDropdownList } from '../../hooks/useDropdownList';
55
58
  import { useMyMetadata } from '../../hooks/useMetadata';
56
59
  import { useUnreadPollQuizPresent } from '../../hooks/useUnreadPollQuizPresent';
57
- import { useLandscapeHLSStream, useMobileHLSStream } from '../../../common/hooks';
60
+ import { useLandscapeHLSStream, useMobileHLSStream, useRecordingHandler } from '../../../common/hooks';
58
61
  // @ts-ignore: No implicit any
59
62
  import { getFormattedCount } from '../../../common/utils';
60
63
  // @ts-ignore: No implicit any
@@ -88,7 +91,6 @@ export const MwebOptions = ({
88
91
  const [openSettingsSheet, setOpenSettingsSheet] = useState(false);
89
92
  const [showEmojiCard, setShowEmojiCard] = useState(false);
90
93
  const [showRecordingOn, setShowRecordingOn] = useState(false);
91
- const [isRecordingLoading, setIsRecordingLoading] = useState(false);
92
94
  const toggleParticipants = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS);
93
95
  const { showPolls } = useShowPolls();
94
96
  const togglePollView = usePollViewToggle();
@@ -102,7 +104,11 @@ export const MwebOptions = ({
102
104
  const isLandscapeHLSStream = useLandscapeHLSStream();
103
105
  const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB);
104
106
  const isLocalVideoEnabled = useHMSStore(selectIsLocalVideoEnabled);
107
+ const { startRecording, isRecordingLoading } = useRecordingHandler();
105
108
 
109
+ const isCaptionPresent = useHMSStore(selectIsTranscriptionEnabled);
110
+
111
+ const [isCaptionEnabled, setIsCaptionEnabled] = useSetIsCaptionEnabled();
106
112
  useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
107
113
 
108
114
  const updateState = (modalName: string, value: boolean) => {
@@ -187,6 +193,20 @@ export const MwebOptions = ({
187
193
  <ActionTile.Title>{isHandRaised ? 'Lower' : 'Raise'} Hand</ActionTile.Title>
188
194
  </ActionTile.Root>
189
195
  ) : null}
196
+ {isCaptionPresent && screenType !== 'hls_live_streaming' ? (
197
+ <ActionTile.Root
198
+ onClick={() => {
199
+ setIsCaptionEnabled(!isCaptionEnabled);
200
+ }}
201
+ >
202
+ {isCaptionEnabled ? (
203
+ <ClosedCaptionIcon width="20" height="20px" />
204
+ ) : (
205
+ <OpenCaptionIcon width="20" height="20px" />
206
+ )}
207
+ <ActionTile.Title>{isCaptionEnabled ? 'Hide Captions' : 'Captions Disabled'}</ActionTile.Title>
208
+ </ActionTile.Root>
209
+ ) : null}
190
210
 
191
211
  {isLocalVideoEnabled && !!elements?.virtual_background ? (
192
212
  <ActionTile.Root
@@ -260,29 +280,8 @@ export const MwebOptions = ({
260
280
  setShowRecordingOn(true);
261
281
  } else {
262
282
  // start recording
263
- setIsRecordingLoading(true);
264
- try {
265
- await hmsActions.startRTMPOrRecording({
266
- record: true,
267
- });
268
- setOpenOptionsSheet(false);
269
- setIsRecordingLoading(false);
270
- } catch (error) {
271
- // @ts-ignore
272
- if (error.message.includes('stream already running')) {
273
- ToastManager.addToast({
274
- title: 'Recording already running',
275
- variant: 'error',
276
- });
277
- } else {
278
- ToastManager.addToast({
279
- // @ts-ignore
280
- title: error.message,
281
- variant: 'error',
282
- });
283
- }
284
- setIsRecordingLoading(false);
285
- }
283
+ await startRecording();
284
+ setOpenOptionsSheet(false);
286
285
  }
287
286
  if (isHLSRunning) {
288
287
  setOpenOptionsSheet(false);
@@ -7,11 +7,7 @@ import { useSetSubscribedChatSelector, useSubscribedNotifications } from '../App
7
7
  // @ts-ignore: No implicit Any
8
8
  import { CHAT_SELECTOR, SUBSCRIBED_NOTIFICATIONS } from '../../common/constants';
9
9
 
10
- const notificationTypes = [
11
- HMSNotificationTypes.PEER_LIST,
12
- HMSNotificationTypes.PEER_JOINED,
13
- HMSNotificationTypes.PEER_LEFT,
14
- ];
10
+ const notificationTypes = [HMSNotificationTypes.PEER_JOINED, HMSNotificationTypes.PEER_LEFT];
15
11
 
16
12
  export const PeerNotifications = () => {
17
13
  const notification = useHMSNotifications(notificationTypes);
@@ -26,11 +22,6 @@ export const PeerNotifications = () => {
26
22
 
27
23
  console.debug(`[${notification.type}]`, notification);
28
24
  switch (notification.type) {
29
- case HMSNotificationTypes.PEER_LIST:
30
- if (!isPeerJoinSubscribed || notification.data.length === 0) {
31
- return;
32
- }
33
- break;
34
25
  case HMSNotificationTypes.PEER_JOINED:
35
26
  if (!isPeerJoinSubscribed) {
36
27
  return;
@@ -47,7 +38,6 @@ export const PeerNotifications = () => {
47
38
  default:
48
39
  return;
49
40
  }
50
-
51
41
  ToastBatcher.showToast({ notification });
52
42
  }, [notification, isPeerJoinSubscribed, isPeerLeftSubscribed, selectedPeer.id, setPeerSelector]);
53
43
 
@@ -2,6 +2,7 @@ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'reac
2
2
  import { useMeasure, useMedia } from 'react-use';
3
3
  import {
4
4
  HMSRoomState,
5
+ selectAppData,
5
6
  selectIsLocalVideoEnabled,
6
7
  selectLocalPeer,
7
8
  selectRoomState,
@@ -16,24 +17,17 @@ import { MicOffIcon, SettingsIcon } from '@100mslive/react-icons';
16
17
  import { Avatar, Box, config as cssConfig, Flex, flexCenter, styled, StyledVideoTile, Text, Video } from '../../..';
17
18
  import { AudioLevel } from '../../../AudioLevel';
18
19
  import { useHMSPrebuiltContext } from '../../AppContext';
19
- // @ts-ignore: No implicit Any
20
20
  import IconButton from '../../IconButton';
21
21
  import SidePane from '../../layouts/SidePane';
22
- // @ts-ignore: No implicit Any
23
22
  import { AudioVideoToggle } from '../AudioVideoToggle';
24
- // @ts-ignore: No implicit Any
25
23
  import Chip from '../Chip';
26
- // @ts-ignore: No implicit Any
27
24
  import TileConnection from '../Connection/TileConnection';
28
- // @ts-ignore: No implicit Any
29
25
  import FullPageProgress from '../FullPageProgress';
30
26
  // @ts-ignore: No implicit Any
31
27
  import { Logo } from '../Header/HeaderComponents';
32
28
  // @ts-ignore: No implicit Any
33
29
  import SettingsModal from '../Settings/SettingsModal';
34
- // @ts-ignore: No implicit Any
35
30
  import { VBToggle } from '../VirtualBackground/VBToggle';
36
- // @ts-ignore: No implicit Any
37
31
  import PreviewForm from './PreviewForm';
38
32
  import { useRoomLayoutPreviewScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
39
33
  // @ts-ignore: No implicit Any
@@ -42,7 +36,7 @@ import { useAuthToken, useUISettings } from '../AppData/useUISettings';
42
36
  import { defaultPreviewPreference, UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
43
37
  // @ts-ignore: No implicit Any
44
38
  import { calculateAvatarAndAttribBoxSize, getFormattedCount } from '../../common/utils';
45
- import { UI_SETTINGS } from '../../common/constants';
39
+ import { APP_DATA, UI_SETTINGS } from '../../common/constants';
46
40
 
47
41
  const getParticipantChipContent = (peerCount = 0) => {
48
42
  if (peerCount === 0) {
@@ -85,6 +79,7 @@ const PreviewJoin = ({
85
79
  const [previewError, setPreviewError] = useState(false);
86
80
  const { endpoints } = useHMSPrebuiltContext();
87
81
  const { peerCount } = useParticipants();
82
+ const loadingEffects = useHMSStore(selectAppData(APP_DATA.loadingEffects));
88
83
  const { enableJoin, preview, join } = usePreviewJoin({
89
84
  name,
90
85
  token: authToken,
@@ -166,7 +161,7 @@ const PreviewJoin = ({
166
161
  name={name}
167
162
  disabled={!!initialName}
168
163
  onChange={setName}
169
- enableJoin={enableJoin}
164
+ enableJoin={enableJoin && !loadingEffects}
170
165
  onJoin={savePreferenceAndJoin}
171
166
  cannotPublishVideo={!toggleVideo}
172
167
  cannotPublishAudio={!toggleAudio}
@@ -3,14 +3,11 @@ import { useSearchParam } from 'react-use';
3
3
  import { Flex } from '../../..';
4
4
  import { useHMSPrebuiltContext } from '../../AppContext';
5
5
  import { useRoomLayout } from '../../provider/roomLayoutProvider';
6
- // @ts-ignore: No implicit Any
7
6
  import FullPageProgress from '../FullPageProgress';
8
- // @ts-ignore: No implicit Any
9
7
  import PreviewJoin from './PreviewJoin';
10
8
  import { useRoomLayoutPreviewScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
11
9
  // @ts-ignore: No implicit Any
12
10
  import { useAuthToken } from '../AppData/useUISettings';
13
- // @ts-ignore: No implicit Any
14
11
  import { QUERY_PARAM_PREVIEW_AS_ROLE } from '../../common/constants';
15
12
 
16
13
  export const PreviewScreen = () => {
@@ -4,27 +4,13 @@ import { AlertTriangleIcon } from '@100mslive/react-icons';
4
4
  import { Button, Dialog, Flex, Text } from '../../../';
5
5
  import { ResolutionInput } from '../Streaming/ResolutionInput';
6
6
  import { ToastManager } from '../Toast/ToastManager';
7
- import { useSetAppDataByKey } from '../AppData/useUISettings';
8
- import { APP_DATA, RTMP_RECORD_DEFAULT_RESOLUTION } from '../../common/constants';
9
-
10
- export function getResolution(recordingResolution) {
11
- const resolution = {};
12
- if (recordingResolution.width) {
13
- resolution.width = recordingResolution.width;
14
- }
15
- if (recordingResolution.height) {
16
- resolution.height = recordingResolution.height;
17
- }
18
- if (Object.keys(resolution).length > 0) {
19
- return resolution;
20
- }
21
- }
7
+ import { useRecordingHandler } from '../../common/hooks';
8
+ import { RTMP_RECORD_DEFAULT_RESOLUTION } from '../../common/constants';
22
9
 
23
10
  const StartRecording = ({ open, onOpenChange }) => {
24
11
  const permissions = useHMSStore(selectPermissions);
25
12
  const [resolution, setResolution] = useState(RTMP_RECORD_DEFAULT_RESOLUTION);
26
-
27
- const [recordingStarted, setRecordingState] = useSetAppDataByKey(APP_DATA.recordingStarted);
13
+ const { startRecording, recordingStarted } = useRecordingHandler();
28
14
  const { isBrowserRecordingOn, isStreamingOn, isHLSRunning } = useRecordingStreaming();
29
15
  const hmsActions = useHMSActions();
30
16
  if (!permissions?.browserRecording || isHLSRunning) {
@@ -101,26 +87,7 @@ const StartRecording = ({ open, onOpenChange }) => {
101
87
  type="submit"
102
88
  disabled={recordingStarted || isStreamingOn}
103
89
  onClick={async () => {
104
- try {
105
- setRecordingState(true);
106
- await hmsActions.startRTMPOrRecording({
107
- resolution: getResolution(resolution),
108
- record: true,
109
- });
110
- } catch (error) {
111
- if (error.message.includes('stream already running')) {
112
- ToastManager.addToast({
113
- title: 'Recording already running',
114
- variant: 'error',
115
- });
116
- } else {
117
- ToastManager.addToast({
118
- title: error.message,
119
- variant: 'error',
120
- });
121
- }
122
- setRecordingState(false);
123
- }
90
+ await startRecording(resolution);
124
91
  onOpenChange(false);
125
92
  }}
126
93
  >