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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  >