@100mslive/roomkit-react 0.2.8-alpha.2 → 0.2.8-alpha.4
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-CEPQ23TO.js → HLSView-UIPDGADR.js} +509 -234
- package/dist/HLSView-UIPDGADR.js.map +7 -0
- package/dist/Prebuilt/common/hooks.d.ts +3 -0
- package/dist/Prebuilt/components/HMSVideo/FullscreenButton.d.ts +5 -0
- package/dist/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.d.ts +5 -0
- package/dist/Prebuilt/components/HMSVideo/HLSCaptionSelector.d.ts +1 -2
- package/dist/Prebuilt/components/HMSVideo/HLSQualitySelector.d.ts +12 -0
- package/dist/Prebuilt/components/HMSVideo/MwebHLSViewTitle.d.ts +2 -0
- package/dist/Prebuilt/components/HMSVideo/PlayButton.d.ts +6 -0
- package/dist/Prebuilt/components/HMSVideo/PlayerContext.d.ts +8 -0
- package/dist/Prebuilt/components/HMSVideo/VideoProgress.d.ts +2 -0
- package/dist/Prebuilt/components/HMSVideo/VideoTime.d.ts +2 -0
- package/dist/Prebuilt/components/HMSVideo/VolumeControl.d.ts +2 -0
- package/dist/Prebuilt/components/HMSVideo/index.d.ts +17 -0
- package/dist/Prebuilt/components/HMSVideo/utils.d.ts +9 -0
- package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +1 -3
- package/dist/Prebuilt/components/MwebLandscapePrompt.d.ts +1 -1
- package/dist/Prebuilt/components/RaiseHand.d.ts +2 -0
- package/dist/Prebuilt/components/SidePaneTabs.d.ts +1 -0
- package/dist/{chunk-2Y4FJB25.js → chunk-J4NOQ2YL.js} +562 -450
- package/dist/chunk-J4NOQ2YL.js.map +7 -0
- package/dist/index.cjs.js +1556 -1145
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +429 -156
- package/dist/meta.esbuild.json +445 -164
- package/package.json +6 -6
- package/src/Prebuilt/common/hooks.ts +21 -0
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +26 -10
- package/src/Prebuilt/components/ConferenceScreen.tsx +34 -2
- package/src/Prebuilt/components/Footer/Footer.tsx +0 -1
- package/src/Prebuilt/components/HMSVideo/Controls.jsx +1 -1
- package/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx +13 -0
- package/src/Prebuilt/components/HMSVideo/{HLSAutoplayBlockedPrompt.jsx → HLSAutoplayBlockedPrompt.tsx} +13 -6
- package/src/Prebuilt/components/HMSVideo/HLSCaptionSelector.tsx +4 -2
- package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.tsx +241 -0
- package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +3 -0
- package/src/Prebuilt/components/HMSVideo/MwebHLSViewTitle.tsx +91 -0
- package/src/Prebuilt/components/HMSVideo/PlayButton.tsx +27 -0
- package/src/Prebuilt/components/HMSVideo/PlayerContext.tsx +15 -0
- package/src/Prebuilt/components/HMSVideo/VideoProgress.tsx +81 -0
- package/src/Prebuilt/components/HMSVideo/VideoTime.tsx +42 -0
- package/src/Prebuilt/components/HMSVideo/{VolumeControl.jsx → VolumeControl.tsx} +7 -5
- package/src/Prebuilt/components/HMSVideo/{index.js → index.ts} +2 -0
- package/src/Prebuilt/components/HMSVideo/utils.ts +35 -0
- package/src/Prebuilt/components/Leave/LeaveRoom.tsx +7 -1
- package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +38 -25
- package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +3 -1
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +1 -1
- package/src/Prebuilt/components/MwebLandscapePrompt.tsx +5 -0
- package/src/Prebuilt/components/{RaiseHand.jsx → RaiseHand.tsx} +3 -2
- package/src/Prebuilt/components/SidePaneTabs.tsx +29 -10
- package/src/Prebuilt/layouts/HLSView.jsx +272 -156
- package/src/Prebuilt/layouts/SidePane.tsx +21 -10
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +11 -1
- package/dist/HLSView-CEPQ23TO.js.map +0 -7
- package/dist/chunk-2Y4FJB25.js.map +0 -7
- package/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx +0 -18
- package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +0 -127
- package/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.js +0 -27
- package/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +0 -76
- package/src/Prebuilt/components/HMSVideo/VideoTime.jsx +0 -33
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"prebuilt",
|
|
11
11
|
"roomkit"
|
|
12
12
|
],
|
|
13
|
-
"version": "0.2.8-alpha.
|
|
13
|
+
"version": "0.2.8-alpha.4",
|
|
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.2.8-alpha.
|
|
85
|
+
"@100mslive/hls-player": "0.2.8-alpha.4",
|
|
86
86
|
"@100mslive/hms-noise-cancellation": "0.0.0-alpha.1",
|
|
87
|
-
"@100mslive/hms-virtual-background": "1.12.8-alpha.
|
|
88
|
-
"@100mslive/react-icons": "0.9.8-alpha.
|
|
89
|
-
"@100mslive/react-sdk": "0.9.8-alpha.
|
|
87
|
+
"@100mslive/hms-virtual-background": "1.12.8-alpha.4",
|
|
88
|
+
"@100mslive/react-icons": "0.9.8-alpha.4",
|
|
89
|
+
"@100mslive/react-sdk": "0.9.8-alpha.4",
|
|
90
90
|
"@100mslive/types-prebuilt": "0.12.7",
|
|
91
91
|
"@emoji-mart/data": "^1.0.6",
|
|
92
92
|
"@emoji-mart/react": "^1.0.1",
|
|
@@ -121,5 +121,5 @@
|
|
|
121
121
|
"uuid": "^8.3.2",
|
|
122
122
|
"worker-timers": "^7.0.40"
|
|
123
123
|
},
|
|
124
|
-
"gitHead": "
|
|
124
|
+
"gitHead": "ec046697fe2d6a12f4be23b04f217cf38e63af34"
|
|
125
125
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useMedia } from 'react-use';
|
|
2
3
|
import { JoinForm_JoinBtnType } from '@100mslive/types-prebuilt/elements/join_form';
|
|
3
4
|
import {
|
|
5
|
+
parsedUserAgent,
|
|
4
6
|
selectAvailableRoleNames,
|
|
5
7
|
selectIsConnectedToRoom,
|
|
6
8
|
selectPeerCount,
|
|
@@ -10,6 +12,7 @@ import {
|
|
|
10
12
|
useHMSStore,
|
|
11
13
|
useHMSVanillaStore,
|
|
12
14
|
} from '@100mslive/react-sdk';
|
|
15
|
+
import { config } from '../../Theme';
|
|
13
16
|
import { useRoomLayout } from '../provider/roomLayoutProvider';
|
|
14
17
|
import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
|
15
18
|
import { CHAT_SELECTOR } from './constants';
|
|
@@ -100,3 +103,21 @@ export const useParticipants = (params?: { metadata?: { isHandRaised?: boolean }
|
|
|
100
103
|
}
|
|
101
104
|
return { participants: participantList, isConnected, peerCount, rolesWithParticipants };
|
|
102
105
|
};
|
|
106
|
+
|
|
107
|
+
export const useIsLandscape = () => {
|
|
108
|
+
const isMobile = parsedUserAgent.getDevice().type === 'mobile';
|
|
109
|
+
const isLandscape = useMedia(config.media.ls);
|
|
110
|
+
return isMobile && isLandscape;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const useLandscapeHLSStream = () => {
|
|
114
|
+
const isLandscape = useIsLandscape();
|
|
115
|
+
const { screenType } = useRoomLayoutConferencingScreen();
|
|
116
|
+
return isLandscape && screenType === 'hls_live_streaming';
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const useMobileHLSStream = () => {
|
|
120
|
+
const isMobile = useMedia(config.media.md);
|
|
121
|
+
const { screenType } = useRoomLayoutConferencingScreen();
|
|
122
|
+
return isMobile && screenType === 'hls_live_streaming';
|
|
123
|
+
};
|
|
@@ -2,10 +2,12 @@ import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'reac
|
|
|
2
2
|
import { useMedia } from 'react-use';
|
|
3
3
|
import data from '@emoji-mart/data';
|
|
4
4
|
import Picker from '@emoji-mart/react';
|
|
5
|
-
import { HMSException, selectLocalPeer, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
|
5
|
+
import { HMSException, selectLocalPeer, useAVToggle, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
|
6
6
|
import { EmojiIcon, PauseCircleIcon, SendIcon, VerticalMenuIcon } from '@100mslive/react-icons';
|
|
7
7
|
import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled, Text } from '../../..';
|
|
8
8
|
import { IconButton } from '../../../IconButton';
|
|
9
|
+
import { MoreSettings } from '../MoreSettings/MoreSettings';
|
|
10
|
+
import { RaiseHand } from '../RaiseHand';
|
|
9
11
|
// @ts-ignore
|
|
10
12
|
import { ToastManager } from '../Toast/ToastManager';
|
|
11
13
|
import { ChatSelectorContainer } from './ChatSelectorContainer';
|
|
@@ -17,7 +19,7 @@ import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppDa
|
|
|
17
19
|
import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
|
|
18
20
|
// @ts-ignore
|
|
19
21
|
import { useEmojiPickerStyles } from './useEmojiPickerStyles';
|
|
20
|
-
import { useDefaultChatSelection } from '../../common/hooks';
|
|
22
|
+
import { useDefaultChatSelection, useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
|
|
21
23
|
import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
|
|
22
24
|
|
|
23
25
|
const TextArea = styled('textarea', {
|
|
@@ -77,7 +79,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
|
77
79
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
78
80
|
const [draftMessage, setDraftMessage] = useChatDraftMessage();
|
|
79
81
|
const isMobile = useMedia(cssConfig.media.md);
|
|
80
|
-
const { elements } = useRoomLayoutConferencingScreen();
|
|
82
|
+
const { elements, screenType } = useRoomLayoutConferencingScreen();
|
|
81
83
|
const message_placeholder = elements?.chat?.message_placeholder || 'Send a message';
|
|
82
84
|
const localPeer = useHMSStore(selectLocalPeer);
|
|
83
85
|
const isOverlayChat = elements?.chat?.is_overlay;
|
|
@@ -87,18 +89,21 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
|
87
89
|
const defaultSelection = useDefaultChatSelection();
|
|
88
90
|
const selection = selectedPeer.name || selectedRole || defaultSelection;
|
|
89
91
|
const isLocalPeerBlacklisted = useIsPeerBlacklisted({ local: true });
|
|
92
|
+
const { toggleAudio, toggleVideo } = useAVToggle();
|
|
93
|
+
const noAVPermissions = !(toggleAudio || toggleVideo);
|
|
94
|
+
const isMwebHLSStream = useMobileHLSStream();
|
|
95
|
+
const isLandscapeHLSStream = useLandscapeHLSStream();
|
|
90
96
|
|
|
91
97
|
useEffect(() => {
|
|
92
98
|
if (!selectedPeer.id && !selectedRole && !['Everyone', ''].includes(defaultSelection)) {
|
|
93
99
|
setRoleSelector(defaultSelection);
|
|
94
100
|
} else {
|
|
95
101
|
// @ts-ignore
|
|
96
|
-
if (!elements?.chat?.disable_autofocus) {
|
|
102
|
+
if (!(isMobile || isLandscapeHLSStream) || !elements?.chat?.disable_autofocus) {
|
|
97
103
|
inputRef.current?.focus();
|
|
98
104
|
}
|
|
99
105
|
}
|
|
100
|
-
|
|
101
|
-
}, [defaultSelection, elements?.chat?.disable_autofocus, selectedPeer, selectedRole, setRoleSelector]);
|
|
106
|
+
}, [defaultSelection, selectedPeer, selectedRole, setRoleSelector, isMobile, isLandscapeHLSStream, elements?.chat]);
|
|
102
107
|
const sendMessage = useCallback(async () => {
|
|
103
108
|
const message = inputRef?.current?.value;
|
|
104
109
|
if (!message || !message.trim().length) {
|
|
@@ -197,18 +202,17 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
|
197
202
|
align="center"
|
|
198
203
|
css={{
|
|
199
204
|
bg: isOverlayChat && isMobile ? '$surface_dim' : '$surface_default',
|
|
200
|
-
minHeight: '$16',
|
|
201
205
|
maxHeight: '$24',
|
|
202
206
|
position: 'relative',
|
|
203
|
-
py: '$6',
|
|
204
207
|
pl: '$8',
|
|
205
|
-
flexGrow: 1,
|
|
208
|
+
flexGrow: '1',
|
|
206
209
|
r: '$1',
|
|
207
210
|
'@md': {
|
|
208
211
|
minHeight: 'unset',
|
|
209
212
|
h: '$14',
|
|
210
213
|
boxSizing: 'border-box',
|
|
211
214
|
},
|
|
215
|
+
...(isLandscapeHLSStream ? { minHeight: '$14', py: 0 } : {}),
|
|
212
216
|
}}
|
|
213
217
|
>
|
|
214
218
|
{children}
|
|
@@ -223,6 +227,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
|
223
227
|
placeholder={message_placeholder}
|
|
224
228
|
ref={inputRef}
|
|
225
229
|
required
|
|
230
|
+
autoFocus={!(isMobile || isLandscapeHLSStream)}
|
|
226
231
|
onKeyPress={async event => {
|
|
227
232
|
if (event.key === 'Enter') {
|
|
228
233
|
if (!event.shiftKey) {
|
|
@@ -237,7 +242,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
|
237
242
|
onCut={e => e.stopPropagation()}
|
|
238
243
|
onCopy={e => e.stopPropagation()}
|
|
239
244
|
/>
|
|
240
|
-
{!isMobile ? (
|
|
245
|
+
{!isMobile && !isLandscapeHLSStream ? (
|
|
241
246
|
<EmojiPicker
|
|
242
247
|
onSelect={emoji => {
|
|
243
248
|
if (inputRef.current) {
|
|
@@ -260,6 +265,17 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
|
260
265
|
<SendIcon />
|
|
261
266
|
</BaseIconButton>
|
|
262
267
|
</Flex>
|
|
268
|
+
{(isMwebHLSStream || isLandscapeHLSStream) && (
|
|
269
|
+
<Flex
|
|
270
|
+
css={{
|
|
271
|
+
alignItems: 'center',
|
|
272
|
+
}}
|
|
273
|
+
gap="1"
|
|
274
|
+
>
|
|
275
|
+
{noAVPermissions ? <RaiseHand /> : null}
|
|
276
|
+
<MoreSettings elements={elements} screenType={screenType} />
|
|
277
|
+
</Flex>
|
|
278
|
+
)}
|
|
263
279
|
</Flex>
|
|
264
280
|
)}
|
|
265
281
|
</Box>
|
|
@@ -6,10 +6,13 @@ import {
|
|
|
6
6
|
selectAppData,
|
|
7
7
|
selectIsConnectedToRoom,
|
|
8
8
|
selectRoomState,
|
|
9
|
+
useAVToggle,
|
|
9
10
|
useHMSActions,
|
|
10
11
|
useHMSStore,
|
|
11
12
|
} from '@100mslive/react-sdk';
|
|
12
13
|
import { Footer } from './Footer/Footer';
|
|
14
|
+
import { LeaveRoom } from './Leave/LeaveRoom';
|
|
15
|
+
import { MoreSettings } from './MoreSettings/MoreSettings';
|
|
13
16
|
import { HLSFailureModal } from './Notifications/HLSFailureModal';
|
|
14
17
|
// @ts-ignore: No implicit Any
|
|
15
18
|
import { ActivatedPIP } from './PIP/PIPComponent';
|
|
@@ -23,12 +26,14 @@ import { VideoStreamingSection } from '../layouts/VideoStreamingSection';
|
|
|
23
26
|
import FullPageProgress from './FullPageProgress';
|
|
24
27
|
import { Header } from './Header';
|
|
25
28
|
import { PreviousRoleInMetadata } from './PreviousRoleInMetadata';
|
|
29
|
+
import { RaiseHand } from './RaiseHand';
|
|
26
30
|
import {
|
|
27
31
|
useRoomLayoutConferencingScreen,
|
|
28
32
|
useRoomLayoutPreviewScreen,
|
|
29
33
|
} from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
|
30
34
|
// @ts-ignore: No implicit Any
|
|
31
35
|
import { useAuthToken, useSetAppDataByKey } from './AppData/useUISettings';
|
|
36
|
+
import { useLandscapeHLSStream, useMobileHLSStream } from '../common/hooks';
|
|
32
37
|
// @ts-ignore: No implicit Any
|
|
33
38
|
import { APP_DATA, isAndroid, isIOS, isIPadOS } from '../common/constants';
|
|
34
39
|
|
|
@@ -47,12 +52,20 @@ export const ConferenceScreen = () => {
|
|
|
47
52
|
const isMobileDevice = isAndroid || isIOS || isIPadOS;
|
|
48
53
|
const dropdownListRef = useRef<string[]>();
|
|
49
54
|
const [isHLSStarted] = useSetAppDataByKey(APP_DATA.hlsStarted);
|
|
55
|
+
|
|
56
|
+
const { toggleAudio, toggleVideo } = useAVToggle();
|
|
57
|
+
const noAVPermissions = !(toggleAudio || toggleVideo);
|
|
58
|
+
// using it in hls stream to show action button when chat is disabled
|
|
59
|
+
const showChat = !!screenProps.elements?.chat;
|
|
50
60
|
const toggleControls = () => {
|
|
51
61
|
if (dropdownListRef.current?.length === 0 && isMobileDevice) {
|
|
52
62
|
setHideControls(value => !value);
|
|
53
63
|
}
|
|
54
64
|
};
|
|
55
65
|
const autoRoomJoined = useRef(isPreviewScreenEnabled);
|
|
66
|
+
const isMobileHLSStream = useMobileHLSStream();
|
|
67
|
+
const isLandscapeHLSStream = useLandscapeHLSStream();
|
|
68
|
+
const isMwebHLSStream = isMobileHLSStream || isLandscapeHLSStream;
|
|
56
69
|
|
|
57
70
|
useEffect(() => {
|
|
58
71
|
let timeout: undefined | ReturnType<typeof setTimeout>;
|
|
@@ -113,7 +126,7 @@ export const ConferenceScreen = () => {
|
|
|
113
126
|
</Box>
|
|
114
127
|
) : null}
|
|
115
128
|
<Flex css={{ size: '100%', overflow: 'hidden' }} direction="column">
|
|
116
|
-
{!screenProps.hideSections.includes('header') && (
|
|
129
|
+
{!(screenProps.hideSections.includes('header') || isMwebHLSStream) && (
|
|
117
130
|
<Box
|
|
118
131
|
ref={headerRef}
|
|
119
132
|
css={{
|
|
@@ -129,6 +142,11 @@ export const ConferenceScreen = () => {
|
|
|
129
142
|
<Header />
|
|
130
143
|
</Box>
|
|
131
144
|
)}
|
|
145
|
+
{isMwebHLSStream && (
|
|
146
|
+
<Flex align="center" gap="2" css={{ position: 'absolute', left: '$4', top: '$4', zIndex: 1 }}>
|
|
147
|
+
<LeaveRoom screenType={screenProps.screenType} />
|
|
148
|
+
</Flex>
|
|
149
|
+
)}
|
|
132
150
|
<Box
|
|
133
151
|
css={{
|
|
134
152
|
w: '100%',
|
|
@@ -155,7 +173,7 @@ export const ConferenceScreen = () => {
|
|
|
155
173
|
/>
|
|
156
174
|
) : null}
|
|
157
175
|
</Box>
|
|
158
|
-
{!screenProps.hideSections.includes('footer') && screenProps.elements && (
|
|
176
|
+
{!screenProps.hideSections.includes('footer') && screenProps.elements && !isMwebHLSStream && (
|
|
159
177
|
<Box
|
|
160
178
|
ref={footerRef}
|
|
161
179
|
css={{
|
|
@@ -174,6 +192,20 @@ export const ConferenceScreen = () => {
|
|
|
174
192
|
<Footer elements={screenProps.elements} screenType={screenProps.screenType} />
|
|
175
193
|
</Box>
|
|
176
194
|
)}
|
|
195
|
+
{isMwebHLSStream && !showChat && (
|
|
196
|
+
<Flex
|
|
197
|
+
css={{
|
|
198
|
+
alignItems: 'center',
|
|
199
|
+
pr: '$4',
|
|
200
|
+
pb: '$4',
|
|
201
|
+
}}
|
|
202
|
+
justify="end"
|
|
203
|
+
gap="1"
|
|
204
|
+
>
|
|
205
|
+
{noAVPermissions ? <RaiseHand /> : null}
|
|
206
|
+
<MoreSettings elements={screenProps.elements} screenType={screenProps.screenType} />
|
|
207
|
+
</Flex>
|
|
208
|
+
)}
|
|
177
209
|
<RoleChangeRequestModal />
|
|
178
210
|
<HLSFailureModal />
|
|
179
211
|
<ActivatedPIP />
|
|
@@ -12,7 +12,6 @@ import { EmojiReaction } from '../EmojiReaction';
|
|
|
12
12
|
import { LeaveRoom } from '../Leave/LeaveRoom';
|
|
13
13
|
// @ts-ignore: No implicit Any
|
|
14
14
|
import { MoreSettings } from '../MoreSettings/MoreSettings';
|
|
15
|
-
// @ts-ignore: No implicit Any
|
|
16
15
|
import { RaiseHand } from '../RaiseHand';
|
|
17
16
|
// @ts-ignore: No implicit Any
|
|
18
17
|
import { ScreenshareToggle } from '../ScreenShareToggle';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ExpandIcon, ShrinkIcon } from '@100mslive/react-icons';
|
|
3
|
+
import { Flex, IconButton, Tooltip } from '../../..';
|
|
4
|
+
|
|
5
|
+
export const FullScreenButton = ({ isFullScreen, onToggle }: { isFullScreen: boolean; onToggle: () => void }) => {
|
|
6
|
+
return (
|
|
7
|
+
<Tooltip title={`${isFullScreen ? 'Exit' : 'Go'} fullscreen`} side="top">
|
|
8
|
+
<IconButton css={{ margin: '0px' }} onClick={onToggle} key="fullscreen_btn" data-testid="fullscreen_btn">
|
|
9
|
+
<Flex>{isFullScreen ? <ShrinkIcon /> : <ExpandIcon />}</Flex>
|
|
10
|
+
</IconButton>
|
|
11
|
+
</Tooltip>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Button, Dialog, Text } from '
|
|
2
|
+
import { Button, Dialog, Text } from '../../..';
|
|
3
|
+
// @ts-ignore
|
|
3
4
|
import { DialogContent, DialogRow } from '../../primitives/DialogContent';
|
|
4
5
|
|
|
5
|
-
export function HLSAutoplayBlockedPrompt({
|
|
6
|
+
export function HLSAutoplayBlockedPrompt({
|
|
7
|
+
open,
|
|
8
|
+
unblockAutoPlay,
|
|
9
|
+
}: {
|
|
10
|
+
open: boolean;
|
|
11
|
+
unblockAutoPlay: () => Promise<void>;
|
|
12
|
+
}) {
|
|
6
13
|
return (
|
|
7
14
|
<Dialog.Root
|
|
8
15
|
open={open}
|
|
9
|
-
onOpenChange={value => {
|
|
16
|
+
onOpenChange={async value => {
|
|
10
17
|
if (!value) {
|
|
11
|
-
unblockAutoPlay();
|
|
18
|
+
await unblockAutoPlay();
|
|
12
19
|
}
|
|
13
20
|
}}
|
|
14
21
|
>
|
|
@@ -22,8 +29,8 @@ export function HLSAutoplayBlockedPrompt({ open, unblockAutoPlay }) {
|
|
|
22
29
|
<DialogRow justify="end">
|
|
23
30
|
<Button
|
|
24
31
|
variant="primary"
|
|
25
|
-
onClick={() => {
|
|
26
|
-
unblockAutoPlay();
|
|
32
|
+
onClick={async () => {
|
|
33
|
+
await unblockAutoPlay();
|
|
27
34
|
}}
|
|
28
35
|
>
|
|
29
36
|
Play stream
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ClosedCaptionIcon, OpenCaptionIcon } from '@100mslive/react-icons';
|
|
3
3
|
import { IconButton, Tooltip } from '../../../';
|
|
4
|
+
import { useHMSPlayerContext } from './PlayerContext';
|
|
4
5
|
|
|
5
|
-
export function HLSCaptionSelector({ isEnabled
|
|
6
|
+
export function HLSCaptionSelector({ isEnabled }: { isEnabled: boolean }) {
|
|
7
|
+
const { hlsPlayer } = useHMSPlayerContext();
|
|
6
8
|
return (
|
|
7
9
|
<Tooltip title="Subtitles/closed captions" side="top">
|
|
8
|
-
<IconButton css={{ p: '$2' }} onClick={() =>
|
|
10
|
+
<IconButton css={{ p: '$2' }} onClick={() => hlsPlayer?.toggleCaption()}>
|
|
9
11
|
{isEnabled ? <ClosedCaptionIcon width="20" height="20px" /> : <OpenCaptionIcon width="20" height="20px" />}
|
|
10
12
|
</IconButton>
|
|
11
13
|
</Tooltip>
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useMedia } from 'react-use';
|
|
3
|
+
import { HMSHLSLayer } from '@100mslive/hls-player';
|
|
4
|
+
import { CheckIcon, CrossIcon, SettingsIcon } from '@100mslive/react-icons';
|
|
5
|
+
import { Box, Dropdown, Flex, Text, Tooltip } from '../../..';
|
|
6
|
+
import { Sheet } from '../../../Sheet';
|
|
7
|
+
import { config } from '../../../Theme';
|
|
8
|
+
import { useIsLandscape } from '../../common/hooks';
|
|
9
|
+
|
|
10
|
+
export function HLSQualitySelector({
|
|
11
|
+
open,
|
|
12
|
+
onOpenChange,
|
|
13
|
+
layers,
|
|
14
|
+
onQualityChange,
|
|
15
|
+
selection,
|
|
16
|
+
isAuto,
|
|
17
|
+
}: {
|
|
18
|
+
open: boolean;
|
|
19
|
+
onOpenChange: (value: boolean) => void;
|
|
20
|
+
layers: HMSHLSLayer[];
|
|
21
|
+
onQualityChange: (quality: { [key: string]: string | number } | HMSHLSLayer) => void;
|
|
22
|
+
selection: HMSHLSLayer;
|
|
23
|
+
isAuto: boolean;
|
|
24
|
+
}) {
|
|
25
|
+
const isMobile = useMedia(config.media.md);
|
|
26
|
+
const isLandscape = useIsLandscape();
|
|
27
|
+
if (isMobile || isLandscape) {
|
|
28
|
+
return (
|
|
29
|
+
<Sheet.Root open={open} onOpenChange={onOpenChange}>
|
|
30
|
+
<Sheet.Trigger asChild data-testid="quality_selector">
|
|
31
|
+
<Flex
|
|
32
|
+
css={{
|
|
33
|
+
color: '$on_primary_high',
|
|
34
|
+
r: '$1',
|
|
35
|
+
cursor: 'pointer',
|
|
36
|
+
p: '$2',
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
<SettingsIcon />
|
|
40
|
+
</Flex>
|
|
41
|
+
</Sheet.Trigger>
|
|
42
|
+
|
|
43
|
+
{layers.length > 0 && (
|
|
44
|
+
<Sheet.Content css={{ bg: '$surface_default', pb: '$1' }} onClick={() => onOpenChange(false)}>
|
|
45
|
+
<Sheet.Title
|
|
46
|
+
css={{
|
|
47
|
+
display: 'flex',
|
|
48
|
+
color: '$on_surface_high',
|
|
49
|
+
w: '100%',
|
|
50
|
+
justifyContent: 'space-between',
|
|
51
|
+
mt: '$8',
|
|
52
|
+
fontSize: '$md',
|
|
53
|
+
px: '$10',
|
|
54
|
+
pb: '$8',
|
|
55
|
+
borderBottom: '1px solid $border_bright',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
Quality
|
|
60
|
+
<Sheet.Close css={{ color: '$on_surface_high' }} onClick={() => onOpenChange(false)}>
|
|
61
|
+
<CrossIcon />
|
|
62
|
+
</Sheet.Close>
|
|
63
|
+
</Sheet.Title>
|
|
64
|
+
{layers.map(layer => {
|
|
65
|
+
return (
|
|
66
|
+
<Flex
|
|
67
|
+
align="center"
|
|
68
|
+
css={{
|
|
69
|
+
w: '100%',
|
|
70
|
+
bg: '$surface_default',
|
|
71
|
+
'&:hover': {
|
|
72
|
+
bg: '$surface_brighter',
|
|
73
|
+
},
|
|
74
|
+
cursor: 'pointer',
|
|
75
|
+
gap: '$4',
|
|
76
|
+
py: '$8',
|
|
77
|
+
px: '$10',
|
|
78
|
+
}}
|
|
79
|
+
key={layer.width}
|
|
80
|
+
onClick={() => onQualityChange(layer)}
|
|
81
|
+
>
|
|
82
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold' }}>
|
|
83
|
+
{getQualityText(layer)}
|
|
84
|
+
</Text>
|
|
85
|
+
<Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
|
|
86
|
+
{getBitrateText(layer)}
|
|
87
|
+
</Text>
|
|
88
|
+
{!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
|
|
89
|
+
<CheckIcon width="16px" height="16px" />
|
|
90
|
+
)}
|
|
91
|
+
</Flex>
|
|
92
|
+
);
|
|
93
|
+
})}
|
|
94
|
+
<Flex
|
|
95
|
+
align="center"
|
|
96
|
+
css={{
|
|
97
|
+
w: '100%',
|
|
98
|
+
bg: '$surface_default',
|
|
99
|
+
'&:hover': {
|
|
100
|
+
bg: '$surface_brighter',
|
|
101
|
+
},
|
|
102
|
+
cursor: 'pointer',
|
|
103
|
+
gap: '$4',
|
|
104
|
+
py: '$8',
|
|
105
|
+
px: '$10',
|
|
106
|
+
}}
|
|
107
|
+
key="auto"
|
|
108
|
+
onClick={() => onQualityChange({ height: 'auto' })}
|
|
109
|
+
>
|
|
110
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
|
|
111
|
+
Auto
|
|
112
|
+
</Text>
|
|
113
|
+
{isAuto && <CheckIcon width="16px" height="16px" />}
|
|
114
|
+
</Flex>
|
|
115
|
+
</Sheet.Content>
|
|
116
|
+
)}
|
|
117
|
+
</Sheet.Root>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return (
|
|
121
|
+
<Dropdown.Root open={open} onOpenChange={value => onOpenChange(value)}>
|
|
122
|
+
<Dropdown.Trigger asChild data-testid="quality_selector">
|
|
123
|
+
<Flex
|
|
124
|
+
css={{
|
|
125
|
+
color: '$on_primary_high',
|
|
126
|
+
r: '$1',
|
|
127
|
+
cursor: 'pointer',
|
|
128
|
+
p: '$2',
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
<Tooltip title="Select Quality" side="top">
|
|
132
|
+
<Flex align="center">
|
|
133
|
+
<Box
|
|
134
|
+
css={{
|
|
135
|
+
w: '$9',
|
|
136
|
+
h: '$9',
|
|
137
|
+
display: 'inline-flex',
|
|
138
|
+
alignItems: 'center',
|
|
139
|
+
c: '$on_surface_high',
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
<SettingsIcon />
|
|
143
|
+
</Box>
|
|
144
|
+
<Text
|
|
145
|
+
variant={{
|
|
146
|
+
'@md': 'sm',
|
|
147
|
+
'@sm': 'xs',
|
|
148
|
+
'@xs': 'tiny',
|
|
149
|
+
}}
|
|
150
|
+
css={{ display: 'flex', alignItems: 'center', ml: '$2', c: '$on_surface_medium' }}
|
|
151
|
+
>
|
|
152
|
+
{isAuto && (
|
|
153
|
+
<>
|
|
154
|
+
Auto
|
|
155
|
+
<Box
|
|
156
|
+
css={{
|
|
157
|
+
mx: '$2',
|
|
158
|
+
w: '$2',
|
|
159
|
+
h: '$2',
|
|
160
|
+
background: '$on_surface_medium',
|
|
161
|
+
r: '$1',
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
</>
|
|
165
|
+
)}
|
|
166
|
+
{selection && Math.min(selection.width || 0, selection.height || 0)}p
|
|
167
|
+
</Text>
|
|
168
|
+
</Flex>
|
|
169
|
+
</Tooltip>
|
|
170
|
+
</Flex>
|
|
171
|
+
</Dropdown.Trigger>
|
|
172
|
+
{layers.length > 0 && (
|
|
173
|
+
<Dropdown.Content
|
|
174
|
+
sideOffset={5}
|
|
175
|
+
align="end"
|
|
176
|
+
css={{
|
|
177
|
+
height: 'auto',
|
|
178
|
+
maxHeight: '$52',
|
|
179
|
+
w: '$40',
|
|
180
|
+
bg: '$surface_bright',
|
|
181
|
+
py: '$4',
|
|
182
|
+
gap: '$4',
|
|
183
|
+
display: 'grid',
|
|
184
|
+
}}
|
|
185
|
+
>
|
|
186
|
+
{layers.map(layer => {
|
|
187
|
+
return (
|
|
188
|
+
<Dropdown.Item
|
|
189
|
+
onClick={() => onQualityChange(layer)}
|
|
190
|
+
key={layer.width}
|
|
191
|
+
css={{
|
|
192
|
+
bg:
|
|
193
|
+
!isAuto && layer.width === selection?.width && layer.height === selection?.height
|
|
194
|
+
? '$surface_default'
|
|
195
|
+
: '$surface_bright',
|
|
196
|
+
'&:hover': {
|
|
197
|
+
bg: '$surface_brighter',
|
|
198
|
+
},
|
|
199
|
+
p: '$2 $4 $2 $8',
|
|
200
|
+
h: '$12',
|
|
201
|
+
gap: '$2',
|
|
202
|
+
}}
|
|
203
|
+
>
|
|
204
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold' }}>
|
|
205
|
+
{getQualityText(layer)}
|
|
206
|
+
</Text>
|
|
207
|
+
<Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
|
|
208
|
+
{getBitrateText(layer)}
|
|
209
|
+
</Text>
|
|
210
|
+
{!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
|
|
211
|
+
<CheckIcon width="16px" height="16px" />
|
|
212
|
+
)}
|
|
213
|
+
</Dropdown.Item>
|
|
214
|
+
);
|
|
215
|
+
})}
|
|
216
|
+
<Dropdown.Item
|
|
217
|
+
onClick={() => onQualityChange({ height: 'auto' })}
|
|
218
|
+
key="auto"
|
|
219
|
+
css={{
|
|
220
|
+
bg: !isAuto ? '$surface_bright' : '$surface_default',
|
|
221
|
+
'&:hover': {
|
|
222
|
+
bg: '$surface_brighter',
|
|
223
|
+
},
|
|
224
|
+
p: '$2 $4 $2 $8',
|
|
225
|
+
h: '$12',
|
|
226
|
+
gap: '$2',
|
|
227
|
+
}}
|
|
228
|
+
>
|
|
229
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
|
|
230
|
+
Auto
|
|
231
|
+
</Text>
|
|
232
|
+
{isAuto && <CheckIcon width="16px" height="16px" />}
|
|
233
|
+
</Dropdown.Item>
|
|
234
|
+
</Dropdown.Content>
|
|
235
|
+
)}
|
|
236
|
+
</Dropdown.Root>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const getQualityText = (layer: HMSHLSLayer) => `${Math.min(layer.height || 0, layer.width || 0)}p `;
|
|
241
|
+
const getBitrateText = (layer: HMSHLSLayer) => `(${(Number(layer.bitrate / 1000) / 1000).toFixed(2)} Mbps)`;
|
|
@@ -20,6 +20,7 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
|
|
|
20
20
|
},
|
|
21
21
|
'& video::-webkit-media-text-track-display': {
|
|
22
22
|
padding: '0 $4',
|
|
23
|
+
boxShadow: '0px 1px 3px 0px #000000A3',
|
|
23
24
|
},
|
|
24
25
|
'& video::-webkit-media-text-track-container': {
|
|
25
26
|
fontSize: '$space$10 !important',
|
|
@@ -33,6 +34,8 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
|
|
|
33
34
|
flex: '1 1 0',
|
|
34
35
|
margin: '0 auto',
|
|
35
36
|
minHeight: '0',
|
|
37
|
+
objectFit: 'contain',
|
|
38
|
+
width: 'inherit',
|
|
36
39
|
}}
|
|
37
40
|
ref={videoRef}
|
|
38
41
|
playsInline
|