@100mslive/roomkit-react 0.3.10 → 0.3.11-alpha.0
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.
- package/dist/{HLSView-PF44ZBXN.js → HLSView-HJ44JWJK.js} +18 -3
- package/dist/HLSView-HJ44JWJK.js.map +7 -0
- package/dist/{HLSView-6J5FD3IV.css → HLSView-IBWU4R7W.css} +3 -3
- package/dist/{HLSView-6J5FD3IV.css.map → HLSView-IBWU4R7W.css.map} +1 -1
- package/dist/Prebuilt/common/constants.d.ts +0 -2
- package/dist/Prebuilt/common/hooks.d.ts +8 -1
- package/dist/Prebuilt/components/MoreSettings/CaptionContent.d.ts +5 -0
- package/dist/Prebuilt/components/MoreSettings/CaptionModal.d.ts +4 -0
- package/dist/Prebuilt/components/Polls/Voting/StandardVoting.d.ts +4 -2
- package/dist/Prebuilt/components/Polls/Voting/TimedVoting.d.ts +4 -2
- package/dist/Prebuilt/layouts/WaitingView.d.ts +6 -0
- package/dist/{chunk-TUSCTU6T.js → chunk-WDZ4KRYM.js} +2095 -1805
- package/dist/chunk-WDZ4KRYM.js.map +7 -0
- package/dist/index.cjs.css +2 -2
- package/dist/index.cjs.css.map +1 -1
- package/dist/index.cjs.js +2752 -2446
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +292 -114
- package/dist/meta.esbuild.json +311 -132
- package/package.json +7 -7
- package/src/Prebuilt/common/constants.ts +0 -2
- package/src/Prebuilt/common/hooks.ts +34 -1
- package/src/Prebuilt/common/utils.js +11 -11
- package/src/Prebuilt/components/AppData/AppData.tsx +2 -4
- package/src/Prebuilt/components/AppData/useUISettings.js +0 -3
- package/src/Prebuilt/components/Chat/Chat.tsx +26 -6
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +18 -2
- package/src/Prebuilt/components/Chat/ChatStates.tsx +1 -1
- package/src/Prebuilt/components/Footer/ChatToggle.tsx +5 -1
- package/src/Prebuilt/components/Footer/ParticipantList.tsx +4 -2
- package/src/Prebuilt/components/Footer/PollsToggle.tsx +1 -1
- package/src/Prebuilt/components/MoreSettings/CaptionContent.tsx +132 -0
- package/src/Prebuilt/components/MoreSettings/CaptionModal.tsx +37 -0
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +40 -3
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +19 -19
- package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.tsx +2 -15
- package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +71 -66
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +39 -40
- package/src/Prebuilt/components/Polls/Voting/StandardVoting.tsx +12 -6
- package/src/Prebuilt/components/Polls/Voting/TimedVoting.tsx +21 -10
- package/src/Prebuilt/components/Polls/Voting/Voting.tsx +44 -2
- package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +13 -17
- package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +17 -0
- package/src/Prebuilt/layouts/HLSView.jsx +14 -11
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +43 -9
- package/src/Prebuilt/layouts/WaitingView.tsx +52 -0
- package/dist/HLSView-PF44ZBXN.js.map +0 -7
- package/dist/chunk-TUSCTU6T.js.map +0 -7
- package/src/Prebuilt/layouts/NonPublisherView.jsx +0 -51
- package/src/Prebuilt/layouts/WaitingView.jsx +0 -51
package/package.json
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
"prebuilt",
|
11
11
|
"roomkit"
|
12
12
|
],
|
13
|
-
"version": "0.3.
|
13
|
+
"version": "0.3.11-alpha.0",
|
14
14
|
"author": "100ms",
|
15
15
|
"license": "MIT",
|
16
16
|
"repository": {
|
@@ -74,12 +74,12 @@
|
|
74
74
|
"react": ">=17.0.2 <19.0.0"
|
75
75
|
},
|
76
76
|
"dependencies": {
|
77
|
-
"@100mslive/hls-player": "0.3.
|
77
|
+
"@100mslive/hls-player": "0.3.11-alpha.0",
|
78
78
|
"@100mslive/hms-noise-cancellation": "0.0.1",
|
79
|
-
"@100mslive/hms-virtual-background": "1.13.
|
80
|
-
"@100mslive/hms-whiteboard": "0.0.0",
|
81
|
-
"@100mslive/react-icons": "0.10.
|
82
|
-
"@100mslive/react-sdk": "0.10.
|
79
|
+
"@100mslive/hms-virtual-background": "1.13.11-alpha.0",
|
80
|
+
"@100mslive/hms-whiteboard": "0.0.1-alpha.0",
|
81
|
+
"@100mslive/react-icons": "0.10.11-alpha.0",
|
82
|
+
"@100mslive/react-sdk": "0.10.11-alpha.0",
|
83
83
|
"@100mslive/types-prebuilt": "0.12.8",
|
84
84
|
"@emoji-mart/data": "^1.0.6",
|
85
85
|
"@emoji-mart/react": "^1.0.1",
|
@@ -115,5 +115,5 @@
|
|
115
115
|
"uuid": "^8.3.2",
|
116
116
|
"worker-timers": "^7.0.40"
|
117
117
|
},
|
118
|
-
"gitHead": "
|
118
|
+
"gitHead": "a4ed4a99addf5a2e5b923743c65bd20bd41d4175"
|
119
119
|
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import { parsedUserAgent } from '@100mslive/react-sdk';
|
2
2
|
|
3
|
-
export const DEFAULT_WAITING_VIEWER_ROLE = 'waiting-room';
|
4
3
|
export const QUERY_PARAM_SKIP_PREVIEW = 'skip_preview';
|
5
4
|
export const QUERY_PARAM_SKIP_PREVIEW_HEADFUL = 'skip_preview_headful';
|
6
5
|
export const QUERY_PARAM_NAME = 'name';
|
@@ -30,7 +29,6 @@ export const APP_DATA = {
|
|
30
29
|
appConfig: 'appConfig',
|
31
30
|
sidePane: 'sidePane',
|
32
31
|
hlsStats: 'hlsStats',
|
33
|
-
waitingViewerRole: 'waitingViewerRole',
|
34
32
|
subscribedNotifications: 'subscribedNotifications',
|
35
33
|
logo: 'logo',
|
36
34
|
hlsStarted: 'hlsStarted',
|
@@ -1,17 +1,22 @@
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
2
2
|
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
|
+
HMSPeer,
|
6
7
|
HMSRecording,
|
7
8
|
parsedUserAgent,
|
8
9
|
selectAvailableRoleNames,
|
10
|
+
selectIsAllowedToPublish,
|
9
11
|
selectIsConnectedToRoom,
|
12
|
+
selectLocalPeerRole,
|
10
13
|
selectPeerCount,
|
11
14
|
selectPeerMetadata,
|
12
15
|
selectPeers,
|
16
|
+
selectPeersByRoles,
|
13
17
|
selectRecordingState,
|
14
18
|
selectRemotePeers,
|
19
|
+
selectRolesMap,
|
15
20
|
useHMSActions,
|
16
21
|
useHMSStore,
|
17
22
|
useHMSVanillaStore,
|
@@ -218,3 +223,31 @@ export function getResolution(
|
|
218
223
|
}
|
219
224
|
return resolution;
|
220
225
|
}
|
226
|
+
|
227
|
+
export interface WaitingRoomInfo {
|
228
|
+
isNotAllowedToPublish: boolean;
|
229
|
+
isScreenOnlyPublishParams: boolean;
|
230
|
+
hasSubscribedRolePublishing: boolean;
|
231
|
+
}
|
232
|
+
export function useWaitingRoomInfo(): WaitingRoomInfo {
|
233
|
+
const localPeerRole = useHMSStore(selectLocalPeerRole);
|
234
|
+
const { video, audio, screen } = useHMSStore(selectIsAllowedToPublish);
|
235
|
+
const roles = useHMSStore(selectRolesMap);
|
236
|
+
const peersByRoles = useHMSStore(selectPeersByRoles(localPeerRole?.subscribeParams.subscribeToRoles || []));
|
237
|
+
const isNotAllowedToPublish = !(video || audio || screen);
|
238
|
+
const isScreenOnlyPublishParams: boolean = screen && !(video || audio);
|
239
|
+
const hasSubscribedRolePublishing: boolean = useMemo(() => {
|
240
|
+
return peersByRoles.some((peer: HMSPeer) => {
|
241
|
+
if (peer.roleName && roles[peer.roleName] && !peer.isLocal) {
|
242
|
+
return !!roles[peer.roleName].publishParams?.allowed.length;
|
243
|
+
}
|
244
|
+
return false;
|
245
|
+
});
|
246
|
+
}, [peersByRoles, roles]);
|
247
|
+
|
248
|
+
return {
|
249
|
+
isNotAllowedToPublish,
|
250
|
+
isScreenOnlyPublishParams,
|
251
|
+
hasSubscribedRolePublishing,
|
252
|
+
};
|
253
|
+
}
|
@@ -142,22 +142,22 @@ export const getPeerResponses = (questions, peerid, userid) => {
|
|
142
142
|
return questions.map(question =>
|
143
143
|
question.responses?.filter(
|
144
144
|
response =>
|
145
|
-
|
145
|
+
response && (response.peer?.peerid === peerid || response.peer?.userid === userid) && !response.skipped,
|
146
146
|
),
|
147
147
|
);
|
148
148
|
};
|
149
149
|
|
150
|
-
export const
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
export const getIndexToShow = responses => {
|
151
|
+
let lastAttemptedIndex = 0;
|
152
|
+
|
153
|
+
Object.keys(responses).forEach(key => {
|
154
|
+
const keyNum = parseInt(key);
|
155
|
+
if (keyNum > lastAttemptedIndex && responses[key]) {
|
156
|
+
lastAttemptedIndex = keyNum;
|
157
157
|
}
|
158
|
-
}
|
159
|
-
|
160
|
-
return
|
158
|
+
});
|
159
|
+
|
160
|
+
return lastAttemptedIndex + 1;
|
161
161
|
};
|
162
162
|
|
163
163
|
export const getPeerParticipationSummary = (poll, localPeerID, localCustomerUserID) => {
|
@@ -21,7 +21,6 @@ import { useSetAppDataByKey } from './useUISettings';
|
|
21
21
|
import {
|
22
22
|
APP_DATA,
|
23
23
|
CHAT_SELECTOR,
|
24
|
-
DEFAULT_WAITING_VIEWER_ROLE,
|
25
24
|
POLL_STATE,
|
26
25
|
SIDE_PANE_OPTIONS,
|
27
26
|
UI_MODE_GRID,
|
@@ -56,7 +55,6 @@ const initialAppData = {
|
|
56
55
|
[APP_DATA.hlsStarted]: false,
|
57
56
|
[APP_DATA.rtmpStarted]: false,
|
58
57
|
[APP_DATA.recordingStarted]: false,
|
59
|
-
[APP_DATA.waitingViewerRole]: DEFAULT_WAITING_VIEWER_ROLE,
|
60
58
|
[APP_DATA.dropdownList]: [],
|
61
59
|
[APP_DATA.authToken]: '',
|
62
60
|
[APP_DATA.minimiseInset]: false,
|
@@ -68,8 +66,8 @@ const initialAppData = {
|
|
68
66
|
[POLL_STATE.pollInView]: '',
|
69
67
|
[POLL_STATE.view]: '',
|
70
68
|
},
|
71
|
-
// by default
|
72
|
-
[APP_DATA.caption]:
|
69
|
+
// by default on because of on demand now
|
70
|
+
[APP_DATA.caption]: true,
|
73
71
|
};
|
74
72
|
|
75
73
|
export const AppData = React.memo(() => {
|
@@ -48,9 +48,6 @@ export const useSetUiSettings = uiSettingKey => {
|
|
48
48
|
return [value, setValue];
|
49
49
|
};
|
50
50
|
|
51
|
-
export const useWaitingViewerRole = () => {
|
52
|
-
return useHMSStore(selectAppData(APP_DATA.waitingViewerRole));
|
53
|
-
};
|
54
51
|
export const useIsHLSStartedFromUI = () => {
|
55
52
|
return useHMSStore(selectAppData(APP_DATA.hlsStarted));
|
56
53
|
};
|
@@ -10,17 +10,20 @@ import { Box, Flex } from '../../../Layout';
|
|
10
10
|
import { config as cssConfig } from '../../../Theme';
|
11
11
|
// @ts-ignore: No implicit any
|
12
12
|
import { EmojiReaction } from '../EmojiReaction';
|
13
|
+
import { MoreSettings } from '../MoreSettings/MoreSettings';
|
14
|
+
import { RaiseHand } from '../RaiseHand';
|
13
15
|
import { ChatBody } from './ChatBody';
|
14
16
|
import { ChatFooter } from './ChatFooter';
|
15
17
|
import { ChatBlocked, ChatPaused } from './ChatStates';
|
16
18
|
import { PinnedMessage } from './PinnedMessage';
|
17
19
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
18
20
|
import { useSidepaneResetOnLayoutUpdate } from '../AppData/useSidepaneResetOnLayoutUpdate';
|
21
|
+
import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
|
19
22
|
import { useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
|
20
23
|
import { SESSION_STORE_KEY, SIDE_PANE_OPTIONS } from '../../common/constants';
|
21
24
|
|
22
25
|
export const Chat = () => {
|
23
|
-
const { elements } = useRoomLayoutConferencingScreen();
|
26
|
+
const { elements, screenType } = useRoomLayoutConferencingScreen();
|
24
27
|
const listRef = useRef<VariableSizeList | null>(null);
|
25
28
|
const hmsActions = useHMSActions();
|
26
29
|
const vanillaStore = useHMSVanillaStore();
|
@@ -29,6 +32,7 @@ export const Chat = () => {
|
|
29
32
|
const isMobileHLSStream = useMobileHLSStream();
|
30
33
|
const isLandscapeStream = useLandscapeHLSStream();
|
31
34
|
useSidepaneResetOnLayoutUpdate('chat', SIDE_PANE_OPTIONS.CHAT);
|
35
|
+
const isLocalPeerBlacklisted = useIsPeerBlacklisted({ local: true });
|
32
36
|
|
33
37
|
const scrollToBottom = useCallback(
|
34
38
|
(unreadCount = 0) => {
|
@@ -57,20 +61,27 @@ export const Chat = () => {
|
|
57
61
|
>
|
58
62
|
{isMobile && elements?.chat?.is_overlay && !streaming ? null : <PinnedMessage />}
|
59
63
|
<ChatBody ref={listRef} scrollToBottom={scrollToBottom} />
|
60
|
-
|
61
|
-
|
62
|
-
|
64
|
+
<Flex align="center" css={{ w: '100%', gap: '$2' }}>
|
65
|
+
<ChatPaused />
|
66
|
+
<ChatBlocked />
|
67
|
+
{streaming && (!isChatEnabled || isLocalPeerBlacklisted) && (
|
68
|
+
<>
|
69
|
+
<RaiseHand css={{ bg: '$surface_default' }} />
|
70
|
+
<MoreSettings elements={elements} screenType={screenType} />
|
71
|
+
</>
|
72
|
+
)}
|
73
|
+
</Flex>
|
63
74
|
{isMobile && elements?.chat?.is_overlay && !streaming ? <PinnedMessage /> : null}
|
64
75
|
{isChatEnabled ? (
|
65
76
|
<ChatFooter onSend={scrollToBottom}>
|
66
77
|
<NewMessageIndicator scrollToBottom={scrollToBottom} listRef={listRef} />
|
67
78
|
</ChatFooter>
|
68
79
|
) : null}
|
69
|
-
{
|
80
|
+
{streaming && (
|
70
81
|
<Box
|
71
82
|
css={{
|
72
83
|
position: 'absolute',
|
73
|
-
...match({ isLandscapeStream, isMobileHLSStream, isChatEnabled })
|
84
|
+
...match({ isLandscapeStream, isMobileHLSStream, isChatEnabled, isLocalPeerBlacklisted })
|
74
85
|
.with(
|
75
86
|
{
|
76
87
|
isLandscapeStream: true,
|
@@ -96,6 +107,7 @@ export const Chat = () => {
|
|
96
107
|
{
|
97
108
|
isMobileHLSStream: true,
|
98
109
|
isChatEnabled: true,
|
110
|
+
isLocalPeerBlacklisted: false,
|
99
111
|
},
|
100
112
|
() => ({ bottom: '$17', right: '$8' }),
|
101
113
|
)
|
@@ -103,6 +115,14 @@ export const Chat = () => {
|
|
103
115
|
{
|
104
116
|
isLandscapeStream: false,
|
105
117
|
isChatEnabled: true,
|
118
|
+
isLocalPeerBlacklisted: true,
|
119
|
+
},
|
120
|
+
() => ({ bottom: '$18', right: '$8' }),
|
121
|
+
)
|
122
|
+
.with(
|
123
|
+
{
|
124
|
+
isMobileHLSStream: true,
|
125
|
+
isLocalPeerBlacklisted: true,
|
106
126
|
},
|
107
127
|
() => ({ bottom: '$20', right: '$8' }),
|
108
128
|
)
|
@@ -102,6 +102,19 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
102
102
|
}
|
103
103
|
}
|
104
104
|
}, [defaultSelection, selectedPeer, selectedRole, setRoleSelector, isMobile, isLandscapeHLSStream, elements?.chat]);
|
105
|
+
|
106
|
+
const resetInputHeight = useCallback(() => {
|
107
|
+
if (inputRef.current) {
|
108
|
+
inputRef.current.style.height = `${Math.max(32, inputRef.current.value ? inputRef.current.scrollHeight : 0)}px`;
|
109
|
+
}
|
110
|
+
}, []);
|
111
|
+
|
112
|
+
const updateInputHeight = useCallback(() => {
|
113
|
+
if (inputRef.current) {
|
114
|
+
inputRef.current.style.height = `${Math.max(32, Math.min(inputRef.current.scrollHeight, 24 * 4))}px`;
|
115
|
+
}
|
116
|
+
}, []);
|
117
|
+
|
105
118
|
const sendMessage = useCallback(async () => {
|
106
119
|
const message = inputRef?.current?.value;
|
107
120
|
if (!message || !message.trim().length) {
|
@@ -116,6 +129,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
116
129
|
await hmsActions.sendBroadcastMessage(message);
|
117
130
|
}
|
118
131
|
inputRef.current.value = '';
|
132
|
+
resetInputHeight();
|
119
133
|
setTimeout(() => {
|
120
134
|
onSend(1);
|
121
135
|
}, 0);
|
@@ -131,6 +145,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
131
145
|
const messageElement = inputRef.current;
|
132
146
|
if (messageElement) {
|
133
147
|
messageElement.value = draftMessage;
|
148
|
+
updateInputHeight();
|
134
149
|
}
|
135
150
|
}, [draftMessage]);
|
136
151
|
|
@@ -197,11 +212,10 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
197
212
|
{selection && (
|
198
213
|
<Flex align="center" css={{ gap: '$4', w: '100%' }}>
|
199
214
|
<Flex
|
200
|
-
align="
|
215
|
+
align="end"
|
201
216
|
css={{
|
202
217
|
bg: isOverlayChat && isMobile ? '$surface_dim' : '$surface_default',
|
203
218
|
minHeight: '$16',
|
204
|
-
maxHeight: '$24',
|
205
219
|
position: 'relative',
|
206
220
|
py: '$6',
|
207
221
|
pl: '$8',
|
@@ -238,6 +252,8 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
238
252
|
}}
|
239
253
|
autoComplete="off"
|
240
254
|
aria-autocomplete="none"
|
255
|
+
onChange={updateInputHeight}
|
256
|
+
onBlur={resetInputHeight}
|
241
257
|
onPaste={e => e.stopPropagation()}
|
242
258
|
onCut={e => e.stopPropagation()}
|
243
259
|
onCopy={e => e.stopPropagation()}
|
@@ -30,7 +30,7 @@ export const ChatPaused = () => {
|
|
30
30
|
<Flex
|
31
31
|
align="center"
|
32
32
|
justify="between"
|
33
|
-
css={{ borderRadius: '$1', bg: '$surface_default', p: '$
|
33
|
+
css={{ borderRadius: '$1', bg: '$surface_default', p: '$2 $4 $2 $8', w: '100%' }}
|
34
34
|
>
|
35
35
|
<Box>
|
36
36
|
<Text variant="sm" css={{ fontWeight: '$semiBold', color: '$on_surface_high' }}>
|
@@ -21,7 +21,11 @@ export const ChatToggle = ({ onClick }: { onClick?: () => void }) => {
|
|
21
21
|
}}
|
22
22
|
>
|
23
23
|
<Tooltip key="chat" title={`${isChatOpen ? 'Close' : 'Open'} chat`}>
|
24
|
-
<IconButton
|
24
|
+
<IconButton
|
25
|
+
onClick={() => (onClick ? onClick() : toggleChat())}
|
26
|
+
css={{ bg: isChatOpen ? '$surface_brighter' : '' }}
|
27
|
+
data-testid="chat_btn"
|
28
|
+
>
|
25
29
|
<ChatIcon />
|
26
30
|
</IconButton>
|
27
31
|
</Tooltip>
|
@@ -86,6 +86,7 @@ export const ParticipantList = ({
|
|
86
86
|
return { ...filterValue };
|
87
87
|
});
|
88
88
|
}, []);
|
89
|
+
|
89
90
|
if (peerCount === 0) {
|
90
91
|
return null;
|
91
92
|
}
|
@@ -128,7 +129,7 @@ export const ParticipantList = ({
|
|
128
129
|
export const ParticipantCount = () => {
|
129
130
|
const peerCount = useHMSStore(selectPeerCount);
|
130
131
|
const toggleSidepane = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS);
|
131
|
-
const
|
132
|
+
const isPeerListOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.PARTICIPANTS);
|
132
133
|
|
133
134
|
if (peerCount === 0) {
|
134
135
|
return null;
|
@@ -139,13 +140,13 @@ export const ParticipantCount = () => {
|
|
139
140
|
w: 'auto',
|
140
141
|
p: '$4',
|
141
142
|
h: 'auto',
|
143
|
+
bg: isPeerListOpen ? '$surface_brighter' : '',
|
142
144
|
}}
|
143
145
|
onClick={() => {
|
144
146
|
if (peerCount > 0) {
|
145
147
|
toggleSidepane();
|
146
148
|
}
|
147
149
|
}}
|
148
|
-
active={!isParticipantsOpen}
|
149
150
|
data-testid="participant_list"
|
150
151
|
>
|
151
152
|
<PeopleIcon />
|
@@ -447,6 +448,7 @@ export const ParticipantSearch = ({
|
|
447
448
|
300,
|
448
449
|
[value, onSearch],
|
449
450
|
);
|
451
|
+
|
450
452
|
return (
|
451
453
|
<Flex
|
452
454
|
align="center"
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { HMSTranscriptionMode, selectIsTranscriptionEnabled, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
3
|
+
import { AlertTriangleIcon, CrossIcon } from '@100mslive/react-icons';
|
4
|
+
import { Button } from '../../../Button';
|
5
|
+
import { Box, Flex } from '../../../Layout';
|
6
|
+
import { Loading } from '../../../Loading';
|
7
|
+
import { Text } from '../../../Text';
|
8
|
+
// @ts-ignore: No implicit Any
|
9
|
+
import { ToastManager } from '../Toast/ToastManager';
|
10
|
+
// @ts-ignore: No implicit Any
|
11
|
+
import { useSetIsCaptionEnabled } from '../AppData/useUISettings';
|
12
|
+
|
13
|
+
export const CaptionContent = ({ isMobile, onExit }: { isMobile: boolean; onExit: () => void }) => {
|
14
|
+
const DURATION = 2000;
|
15
|
+
const actions = useHMSActions();
|
16
|
+
const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
|
17
|
+
|
18
|
+
const [isCaptionEnabled, setIsCaptionEnabled] = useSetIsCaptionEnabled();
|
19
|
+
return (
|
20
|
+
<>
|
21
|
+
<Text
|
22
|
+
variant={isMobile ? 'md' : 'lg'}
|
23
|
+
css={{
|
24
|
+
color: '$on_surface_high',
|
25
|
+
fontWeight: '$semiBold',
|
26
|
+
display: 'flex',
|
27
|
+
pb: '$4',
|
28
|
+
'@md': { px: '$8', borderBottom: '1px solid $border_default' },
|
29
|
+
}}
|
30
|
+
>
|
31
|
+
{isTranscriptionEnabled ? 'Disable' : 'Enable'} Closed Caption (CC) for this session?
|
32
|
+
<Box
|
33
|
+
css={{ color: 'inherit', ml: 'auto', '&:hover': { color: '$on_surface_medium', cursor: 'pointer' } }}
|
34
|
+
onClick={onExit}
|
35
|
+
>
|
36
|
+
<CrossIcon />
|
37
|
+
</Box>
|
38
|
+
</Text>
|
39
|
+
{!isMobile ? (
|
40
|
+
<Text variant="sm" css={{ color: '$on_surface_medium', pb: '$6', mb: '$8', '@md': { px: '$8', mt: '$4' } }}>
|
41
|
+
This will {isTranscriptionEnabled ? 'disable' : 'enable'} Closed Captions for everyone in this room. You can
|
42
|
+
{isTranscriptionEnabled ? 'enable' : 'disable'} it later.
|
43
|
+
</Text>
|
44
|
+
) : null}
|
45
|
+
|
46
|
+
<Flex
|
47
|
+
justify="between"
|
48
|
+
align="center"
|
49
|
+
css={{
|
50
|
+
width: '100%',
|
51
|
+
gap: '$md',
|
52
|
+
mt: '$10',
|
53
|
+
'@md': { px: '$4' },
|
54
|
+
}}
|
55
|
+
>
|
56
|
+
{isMobile ? null : (
|
57
|
+
<Button variant="standard" css={{ w: '100%' }} outlined onClick={onExit}>
|
58
|
+
Cancel
|
59
|
+
</Button>
|
60
|
+
)}
|
61
|
+
<Flex
|
62
|
+
direction="column"
|
63
|
+
justify="between"
|
64
|
+
align="center"
|
65
|
+
css={{
|
66
|
+
width: '100%',
|
67
|
+
}}
|
68
|
+
>
|
69
|
+
{isMobile && isTranscriptionEnabled ? (
|
70
|
+
<Button
|
71
|
+
variant="standard"
|
72
|
+
css={{ w: '100%', mb: '$8' }}
|
73
|
+
outlined
|
74
|
+
onClick={() => {
|
75
|
+
setIsCaptionEnabled(!isCaptionEnabled);
|
76
|
+
onExit();
|
77
|
+
}}
|
78
|
+
>
|
79
|
+
{isCaptionEnabled ? 'Hide For Me' : 'Show For Me'}
|
80
|
+
</Button>
|
81
|
+
) : null}
|
82
|
+
<Button
|
83
|
+
variant={isTranscriptionEnabled ? 'danger' : 'primary'}
|
84
|
+
css={{ width: '100%' }}
|
85
|
+
data-testid="popup_change_btn"
|
86
|
+
onClick={async () => {
|
87
|
+
try {
|
88
|
+
if (isTranscriptionEnabled) {
|
89
|
+
await actions.stopTranscription({
|
90
|
+
mode: HMSTranscriptionMode.CAPTION,
|
91
|
+
});
|
92
|
+
ToastManager.addToast({
|
93
|
+
title: `Disabling Closed Caption for everyone.`,
|
94
|
+
variant: 'standard',
|
95
|
+
duration: DURATION,
|
96
|
+
icon: <Loading color="currentColor" />,
|
97
|
+
});
|
98
|
+
onExit();
|
99
|
+
return;
|
100
|
+
}
|
101
|
+
await actions.startTranscription({
|
102
|
+
mode: HMSTranscriptionMode.CAPTION,
|
103
|
+
});
|
104
|
+
ToastManager.addToast({
|
105
|
+
title: `Enabling Closed Caption for everyone.`,
|
106
|
+
variant: 'standard',
|
107
|
+
duration: DURATION,
|
108
|
+
icon: <Loading color="currentColor" />,
|
109
|
+
});
|
110
|
+
} catch (err) {
|
111
|
+
ToastManager.addToast({
|
112
|
+
title: `Failed to ${isTranscriptionEnabled ? 'disabled' : 'enabled'} closed caption`,
|
113
|
+
variant: 'error',
|
114
|
+
icon: <AlertTriangleIcon style={{ marginRight: '0.5rem' }} />,
|
115
|
+
});
|
116
|
+
}
|
117
|
+
onExit();
|
118
|
+
}}
|
119
|
+
>
|
120
|
+
{isTranscriptionEnabled ? 'Disable' : 'Enable'} for Everyone
|
121
|
+
</Button>
|
122
|
+
</Flex>
|
123
|
+
</Flex>
|
124
|
+
{isMobile && (
|
125
|
+
<Text variant="sm" css={{ color: '$on_surface_medium', pb: '$6', mb: '$8', '@md': { px: '$8', mt: '$4' } }}>
|
126
|
+
This will {isTranscriptionEnabled ? 'disable' : 'enable'} Closed Captions for everyone in this room. You can
|
127
|
+
{isTranscriptionEnabled ? 'enable' : 'disable'} it later.
|
128
|
+
</Text>
|
129
|
+
)}
|
130
|
+
</>
|
131
|
+
);
|
132
|
+
};
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useMedia } from 'react-use';
|
3
|
+
import { config as cssConfig, Dialog } from '../../..';
|
4
|
+
import { Sheet } from '../../../Sheet';
|
5
|
+
import { CaptionContent } from './CaptionContent';
|
6
|
+
|
7
|
+
export const CaptionModal = ({ onOpenChange }: { onOpenChange: (value: boolean) => void }) => {
|
8
|
+
const isMobile = useMedia(cssConfig.media.md);
|
9
|
+
|
10
|
+
const props = {
|
11
|
+
isMobile,
|
12
|
+
onExit: () => {
|
13
|
+
onOpenChange(false);
|
14
|
+
},
|
15
|
+
};
|
16
|
+
|
17
|
+
if (isMobile) {
|
18
|
+
return (
|
19
|
+
<Sheet.Root defaultOpen onOpenChange={onOpenChange}>
|
20
|
+
<Sheet.Content css={{ bg: '$surface_dim', p: '$8 0' }}>
|
21
|
+
<CaptionContent {...props} />
|
22
|
+
</Sheet.Content>
|
23
|
+
</Sheet.Root>
|
24
|
+
);
|
25
|
+
}
|
26
|
+
|
27
|
+
return (
|
28
|
+
<Dialog.Root defaultOpen onOpenChange={onOpenChange}>
|
29
|
+
<Dialog.Portal>
|
30
|
+
<Dialog.Overlay />
|
31
|
+
<Dialog.Content css={{ bg: '$surface_dim', width: 'min(400px,80%)', p: '$10' }}>
|
32
|
+
<CaptionContent {...props} />
|
33
|
+
</Dialog.Content>
|
34
|
+
</Dialog.Portal>
|
35
|
+
</Dialog.Root>
|
36
|
+
);
|
37
|
+
};
|
@@ -6,9 +6,23 @@ import {
|
|
6
6
|
HLSLiveStreamingScreen_Elements,
|
7
7
|
} from '@100mslive/types-prebuilt';
|
8
8
|
import { match } from 'ts-pattern';
|
9
|
-
import {
|
10
|
-
|
11
|
-
|
9
|
+
import {
|
10
|
+
selectAppData,
|
11
|
+
selectIsTranscriptionEnabled,
|
12
|
+
selectLocalPeerID,
|
13
|
+
useHMSActions,
|
14
|
+
useHMSStore,
|
15
|
+
} from '@100mslive/react-sdk';
|
16
|
+
import {
|
17
|
+
BrbIcon,
|
18
|
+
CheckIcon,
|
19
|
+
HamburgerMenuIcon,
|
20
|
+
InfoIcon,
|
21
|
+
OpenCaptionIcon,
|
22
|
+
PipIcon,
|
23
|
+
SettingsIcon,
|
24
|
+
} from '@100mslive/react-icons';
|
25
|
+
import { Checkbox, Dropdown, Flex, Switch, Text, Tooltip } from '../../../..';
|
12
26
|
import IconButton from '../../../IconButton';
|
13
27
|
// @ts-ignore: No implicit any
|
14
28
|
import { PIP } from '../../PIP';
|
@@ -24,6 +38,7 @@ import StartRecording from '../../Settings/StartRecording';
|
|
24
38
|
import { StatsForNerds } from '../../StatsForNerds';
|
25
39
|
// @ts-ignore: No implicit any
|
26
40
|
import { BulkRoleChangeModal } from '../BulkRoleChangeModal';
|
41
|
+
import { CaptionModal } from '../CaptionModal';
|
27
42
|
// @ts-ignore: No implicit any
|
28
43
|
import { FullScreenItem } from '../FullScreenItem';
|
29
44
|
import { MuteAllModal } from '../MuteAllModal';
|
@@ -43,6 +58,7 @@ const MODALS = {
|
|
43
58
|
BULK_ROLE_CHANGE: 'bulkRoleChange',
|
44
59
|
MUTE_ALL: 'muteAll',
|
45
60
|
EMBED_URL: 'embedUrl',
|
61
|
+
CAPTION: 'caption',
|
46
62
|
};
|
47
63
|
|
48
64
|
export const DesktopOptions = ({
|
@@ -59,6 +75,7 @@ export const DesktopOptions = ({
|
|
59
75
|
const { isBRBOn, toggleBRB } = useMyMetadata();
|
60
76
|
const isPipOn = PictureInPicture.isOn();
|
61
77
|
const isBRBEnabled = !!elements?.brb;
|
78
|
+
const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
|
62
79
|
|
63
80
|
useDropdownList({ open: openModals.size > 0, name: 'MoreSettings' });
|
64
81
|
|
@@ -115,6 +132,23 @@ export const DesktopOptions = ({
|
|
115
132
|
</Dropdown.Item>
|
116
133
|
) : null}
|
117
134
|
|
135
|
+
<Dropdown.Item
|
136
|
+
data-testid="closed_caption_admin"
|
137
|
+
onClick={() => {
|
138
|
+
updateState(MODALS.CAPTION, true);
|
139
|
+
}}
|
140
|
+
>
|
141
|
+
<OpenCaptionIcon />
|
142
|
+
<Flex direction="column" css={{ flexGrow: '1' }}>
|
143
|
+
<Text variant="sm" css={{ ml: '$4', color: '$on_surface_high' }}>
|
144
|
+
Closed Captions
|
145
|
+
</Text>
|
146
|
+
<Text variant="caption" css={{ ml: '$4', color: '$on_surface_medium' }}>
|
147
|
+
{isTranscriptionEnabled ? 'Enabled' : 'Disabled'}
|
148
|
+
</Text>
|
149
|
+
</Flex>
|
150
|
+
<Switch id="closed_caption_start_stop" checked={isTranscriptionEnabled} disabled={false} />
|
151
|
+
</Dropdown.Item>
|
118
152
|
{screenType !== 'hls_live_streaming' ? (
|
119
153
|
<Dropdown.Item css={{ p: 0, '&:empty': { display: 'none' } }}>
|
120
154
|
<PIP
|
@@ -211,6 +245,9 @@ export const DesktopOptions = ({
|
|
211
245
|
onOpenChange={(value: boolean) => updateState(MODALS.SELF_ROLE_CHANGE, value)}
|
212
246
|
/>
|
213
247
|
)}
|
248
|
+
{openModals.has(MODALS.CAPTION) && (
|
249
|
+
<CaptionModal onOpenChange={(value: boolean) => updateState(MODALS.CAPTION, value)} />
|
250
|
+
)}
|
214
251
|
{/* {openModals.has(MODALS.EMBED_URL) && (
|
215
252
|
<EmbedUrlModal onOpenChange={value => updateState(MODALS.EMBED_URL, value)} />
|
216
253
|
)} */}
|