@100mslive/roomkit-react 0.2.8-alpha.4 → 0.2.8-alpha.6
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/{HLSView-UIPDGADR.js → HLSView-53PDKIS2.js} +239 -144
- package/dist/HLSView-53PDKIS2.js.map +7 -0
- package/dist/Prebuilt/components/Chat/MwebChatOption.d.ts +1 -1
- package/dist/Prebuilt/components/HMSVideo/PlayPauseButton.d.ts +6 -0
- package/dist/Prebuilt/components/HMSVideo/SeekControls.d.ts +7 -0
- package/dist/Prebuilt/components/HMSVideo/VideoProgress.d.ts +3 -1
- package/dist/Prebuilt/components/HMSVideo/index.d.ts +10 -2
- package/dist/Prebuilt/layouts/SidePane.d.ts +1 -1
- package/dist/{chunk-J4NOQ2YL.js → chunk-2ZFAT7KY.js} +339 -218
- package/dist/chunk-2ZFAT7KY.js.map +7 -0
- package/dist/index.cjs.js +932 -708
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +217 -78
- package/dist/meta.esbuild.json +227 -87
- package/package.json +7 -6
- package/src/Prebuilt/components/AppData/useSidepane.js +17 -2
- package/src/Prebuilt/components/AuthToken.jsx +1 -1
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +1 -1
- package/src/Prebuilt/components/Chat/MwebChatOption.tsx +1 -1
- package/src/Prebuilt/components/ConferenceScreen.tsx +11 -14
- package/src/Prebuilt/components/Footer/RoleOptions.tsx +32 -15
- package/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.tsx +31 -1
- package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +7 -1
- package/src/Prebuilt/components/HMSVideo/PlayPauseButton.tsx +27 -0
- package/src/Prebuilt/components/HMSVideo/SeekControls.tsx +22 -0
- package/src/Prebuilt/components/HMSVideo/VideoProgress.tsx +4 -3
- package/src/Prebuilt/components/HMSVideo/VolumeControl.tsx +1 -1
- package/src/Prebuilt/components/HMSVideo/index.ts +4 -2
- package/src/Prebuilt/components/Header/StreamActions.tsx +1 -1
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +37 -31
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +5 -5
- package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +2 -2
- package/src/Prebuilt/components/Notifications/PeerNotifications.tsx +1 -1
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +19 -8
- package/src/Prebuilt/components/SidePaneTabs.tsx +27 -35
- package/src/Prebuilt/components/StatsForNerds.jsx +14 -6
- package/src/Prebuilt/components/Streaming/Common.jsx +1 -1
- package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +2 -2
- package/src/Prebuilt/components/Toast/ToastBatcher.js +8 -1
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +17 -0
- package/src/Prebuilt/layouts/HLSView.jsx +109 -69
- package/src/Prebuilt/layouts/SidePane.tsx +125 -67
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +2 -1
- package/src/Prebuilt/provider/roomLayoutProvider/index.tsx +1 -1
- package/src/Sheet/Sheet.tsx +4 -0
- package/dist/HLSView-UIPDGADR.js.map +0 -7
- package/dist/chunk-J4NOQ2YL.js.map +0 -7
- package/src/Prebuilt/components/HMSVideo/PlayButton.jsx +0 -13
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.6",
|
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.6",
|
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.6",
|
88
|
+
"@100mslive/react-icons": "0.9.8-alpha.6",
|
89
|
+
"@100mslive/react-sdk": "0.9.8-alpha.6",
|
90
90
|
"@100mslive/types-prebuilt": "0.12.7",
|
91
91
|
"@emoji-mart/data": "^1.0.6",
|
92
92
|
"@emoji-mart/react": "^1.0.1",
|
@@ -118,8 +118,9 @@
|
|
118
118
|
"react-window": "^1.8.7",
|
119
119
|
"recordrtc": "^5.6.2",
|
120
120
|
"screenfull": "^5.1.0",
|
121
|
+
"ts-pattern": "4.3.0",
|
121
122
|
"uuid": "^8.3.2",
|
122
123
|
"worker-timers": "^7.0.40"
|
123
124
|
},
|
124
|
-
"gitHead": "
|
125
|
+
"gitHead": "666634daeed360298e28b87d08d82b96639e0f70"
|
125
126
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { useCallback } from 'react';
|
2
|
+
import { match, P } from 'ts-pattern';
|
2
3
|
import { selectAppData, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
|
3
4
|
import { usePollViewState } from './useUISettings';
|
4
5
|
import { APP_DATA, POLL_STATE, POLL_VIEWS, SIDE_PANE_OPTIONS } from '../../common/constants';
|
@@ -45,8 +46,22 @@ export const usePollViewToggle = () => {
|
|
45
46
|
|
46
47
|
const togglePollView = useCallback(
|
47
48
|
id => {
|
48
|
-
|
49
|
-
|
49
|
+
const newView = match({ id, isOpen, view })
|
50
|
+
.with(
|
51
|
+
{
|
52
|
+
id: P.string,
|
53
|
+
},
|
54
|
+
() => POLL_VIEWS.VOTE,
|
55
|
+
)
|
56
|
+
.with(
|
57
|
+
{
|
58
|
+
isOpen: true,
|
59
|
+
view: P.when(view => !!view),
|
60
|
+
},
|
61
|
+
() => null,
|
62
|
+
)
|
63
|
+
.otherwise(() => POLL_VIEWS.CREATE_POLL_QUIZ);
|
64
|
+
|
50
65
|
setPollState({
|
51
66
|
[POLL_STATE.pollInView]: id,
|
52
67
|
[POLL_STATE.view]: newView,
|
@@ -70,7 +70,7 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint, defaultAuthToken })
|
|
70
70
|
alignItems: 'center',
|
71
71
|
}}
|
72
72
|
>
|
73
|
-
<img src={errorImage} height={80} width={80} />
|
73
|
+
<img src={errorImage} height={80} width={80} alt="Token Error" />
|
74
74
|
<Text variant="h4" css={{ textAlign: 'center', mb: '$4', mt: '$10' }}>
|
75
75
|
{error.title}
|
76
76
|
</Text>
|
@@ -99,7 +99,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
|
|
99
99
|
setRoleSelector(defaultSelection);
|
100
100
|
} else {
|
101
101
|
// @ts-ignore
|
102
|
-
if (!(isMobile || isLandscapeHLSStream)
|
102
|
+
if (!(isMobile || isLandscapeHLSStream) && !elements?.chat?.disable_autofocus) {
|
103
103
|
inputRef.current?.focus();
|
104
104
|
}
|
105
105
|
}
|
@@ -11,7 +11,6 @@ import {
|
|
11
11
|
useHMSStore,
|
12
12
|
} from '@100mslive/react-sdk';
|
13
13
|
import { Footer } from './Footer/Footer';
|
14
|
-
import { LeaveRoom } from './Leave/LeaveRoom';
|
15
14
|
import { MoreSettings } from './MoreSettings/MoreSettings';
|
16
15
|
import { HLSFailureModal } from './Notifications/HLSFailureModal';
|
17
16
|
// @ts-ignore: No implicit Any
|
@@ -57,16 +56,17 @@ export const ConferenceScreen = () => {
|
|
57
56
|
const noAVPermissions = !(toggleAudio || toggleVideo);
|
58
57
|
// using it in hls stream to show action button when chat is disabled
|
59
58
|
const showChat = !!screenProps.elements?.chat;
|
60
|
-
const toggleControls = () => {
|
61
|
-
if (dropdownListRef.current?.length === 0 && isMobileDevice) {
|
62
|
-
setHideControls(value => !value);
|
63
|
-
}
|
64
|
-
};
|
65
59
|
const autoRoomJoined = useRef(isPreviewScreenEnabled);
|
66
60
|
const isMobileHLSStream = useMobileHLSStream();
|
67
61
|
const isLandscapeHLSStream = useLandscapeHLSStream();
|
68
62
|
const isMwebHLSStream = isMobileHLSStream || isLandscapeHLSStream;
|
69
63
|
|
64
|
+
const toggleControls = () => {
|
65
|
+
if (dropdownListRef.current?.length === 0 && isMobileDevice && !isMwebHLSStream) {
|
66
|
+
setHideControls(value => !value);
|
67
|
+
}
|
68
|
+
};
|
69
|
+
|
70
70
|
useEffect(() => {
|
71
71
|
let timeout: undefined | ReturnType<typeof setTimeout>;
|
72
72
|
dropdownListRef.current = dropdownList || [];
|
@@ -118,6 +118,8 @@ export const ConferenceScreen = () => {
|
|
118
118
|
return <FullPageProgress text={roomState === HMSRoomState.Connecting ? 'Joining...' : ''} />;
|
119
119
|
}
|
120
120
|
|
121
|
+
const hideControlsForStreaming = isMwebHLSStream ? true : hideControls;
|
122
|
+
|
121
123
|
return (
|
122
124
|
<>
|
123
125
|
{isHLSStarted ? (
|
@@ -132,7 +134,7 @@ export const ConferenceScreen = () => {
|
|
132
134
|
css={{
|
133
135
|
h: '$18',
|
134
136
|
transition: 'margin 0.3s ease-in-out',
|
135
|
-
marginTop:
|
137
|
+
marginTop: hideControlsForStreaming ? `-${headerRef.current?.clientHeight}px` : 'none',
|
136
138
|
'@md': {
|
137
139
|
h: '$17',
|
138
140
|
},
|
@@ -142,11 +144,6 @@ export const ConferenceScreen = () => {
|
|
142
144
|
<Header />
|
143
145
|
</Box>
|
144
146
|
)}
|
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
|
-
)}
|
150
147
|
<Box
|
151
148
|
css={{
|
152
149
|
w: '100%',
|
@@ -169,7 +166,7 @@ export const ConferenceScreen = () => {
|
|
169
166
|
<VideoStreamingSection
|
170
167
|
screenType={screenProps.screenType}
|
171
168
|
elements={screenProps.elements}
|
172
|
-
hideControls={
|
169
|
+
hideControls={hideControlsForStreaming}
|
173
170
|
/>
|
174
171
|
) : null}
|
175
172
|
</Box>
|
@@ -181,7 +178,7 @@ export const ConferenceScreen = () => {
|
|
181
178
|
maxHeight: '$24',
|
182
179
|
transition: 'margin 0.3s ease-in-out',
|
183
180
|
bg: '$background_dim',
|
184
|
-
marginBottom:
|
181
|
+
marginBottom: hideControlsForStreaming ? `-${footerRef.current?.clientHeight}px` : undefined,
|
185
182
|
'@md': {
|
186
183
|
maxHeight: 'unset',
|
187
184
|
bg: screenProps.screenType === 'hls_live_streaming' ? 'transparent' : '$background_dim',
|
@@ -25,7 +25,12 @@ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvid
|
|
25
25
|
import { getMetadata } from '../../common/utils';
|
26
26
|
|
27
27
|
const dropdownItemCSS = { backgroundColor: '$surface_default', gap: '$4', p: '$8' };
|
28
|
-
const optionTextCSS = {
|
28
|
+
const optionTextCSS = {
|
29
|
+
fontWeight: '$semiBold',
|
30
|
+
color: '$on_surface_high',
|
31
|
+
textTransform: 'none',
|
32
|
+
whiteSpace: 'nowrap',
|
33
|
+
};
|
29
34
|
|
30
35
|
const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleName: string }) => {
|
31
36
|
const vanillaStore = useHMSVanillaStore();
|
@@ -34,8 +39,8 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
|
|
34
39
|
const permissions = useHMSStore(selectPermissions);
|
35
40
|
const role = useHMSStore(selectRoleByRoleName(roleName));
|
36
41
|
|
37
|
-
let
|
38
|
-
let
|
42
|
+
let isVideoOnForSomePeers = false;
|
43
|
+
let isAudioOnForSomePeers = false;
|
39
44
|
|
40
45
|
peerList.forEach(peer => {
|
41
46
|
if (peer.isLocal) {
|
@@ -43,8 +48,8 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
|
|
43
48
|
}
|
44
49
|
const isAudioOn = !!peer.audioTrack && store.tracks[peer.audioTrack]?.enabled;
|
45
50
|
const isVideoOn = !!peer.videoTrack && store.tracks[peer.videoTrack]?.enabled;
|
46
|
-
|
47
|
-
|
51
|
+
isAudioOnForSomePeers = isAudioOnForSomePeers || isAudioOn;
|
52
|
+
isVideoOnForSomePeers = isVideoOnForSomePeers || isVideoOn;
|
48
53
|
});
|
49
54
|
|
50
55
|
const setTrackEnabled = async (type: 'audio' | 'video', enabled = false) => {
|
@@ -55,11 +60,15 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
|
|
55
60
|
}
|
56
61
|
};
|
57
62
|
|
63
|
+
if (!role) {
|
64
|
+
return null;
|
65
|
+
}
|
66
|
+
|
58
67
|
return (
|
59
68
|
<>
|
60
|
-
{role.publishParams.allowed
|
69
|
+
{role.publishParams.allowed.includes('audio') && (
|
61
70
|
<>
|
62
|
-
{
|
71
|
+
{isAudioOnForSomePeers && permissions?.mute ? (
|
63
72
|
<Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', false)}>
|
64
73
|
<MicOffIcon />
|
65
74
|
<Text variant="sm" css={optionTextCSS}>
|
@@ -68,20 +77,20 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
|
|
68
77
|
</Dropdown.Item>
|
69
78
|
) : null}
|
70
79
|
|
71
|
-
{!
|
80
|
+
{!isAudioOnForSomePeers && permissions?.unmute ? (
|
72
81
|
<Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', true)}>
|
73
82
|
<MicOnIcon />
|
74
83
|
<Text variant="sm" css={optionTextCSS}>
|
75
|
-
Unmute Audio for All
|
84
|
+
Request to Unmute Audio for All
|
76
85
|
</Text>
|
77
86
|
</Dropdown.Item>
|
78
87
|
) : null}
|
79
88
|
</>
|
80
89
|
)}
|
81
90
|
|
82
|
-
{role.publishParams.allowed
|
91
|
+
{role.publishParams.allowed.includes('video') && (
|
83
92
|
<>
|
84
|
-
{
|
93
|
+
{isVideoOnForSomePeers && permissions?.mute ? (
|
85
94
|
<Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('video', false)}>
|
86
95
|
<VideoOffIcon />
|
87
96
|
<Text variant="sm" css={optionTextCSS}>
|
@@ -90,11 +99,11 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
|
|
90
99
|
</Dropdown.Item>
|
91
100
|
) : null}
|
92
101
|
|
93
|
-
{!
|
102
|
+
{!isVideoOnForSomePeers && permissions?.unmute ? (
|
94
103
|
<Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('video', true)}>
|
95
104
|
<VideoOnIcon />
|
96
105
|
<Text variant="sm" css={optionTextCSS}>
|
97
|
-
Unmute Video for All
|
106
|
+
Request to Unmute Video for All
|
98
107
|
</Text>
|
99
108
|
</Dropdown.Item>
|
100
109
|
) : null}
|
@@ -112,11 +121,19 @@ export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList
|
|
112
121
|
const { on_stage_role, off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
|
113
122
|
const canMuteOrUnmute = permissions?.mute || permissions?.unmute;
|
114
123
|
const canRemoveRoleFromStage = permissions?.changeRole && roleName === on_stage_role;
|
124
|
+
const role = useHMSStore(selectRoleByRoleName(roleName));
|
125
|
+
|
115
126
|
// on stage and off stage roles
|
116
127
|
const canRemoveRoleFromRoom =
|
117
128
|
permissions?.removeOthers && (on_stage_role === roleName || off_stage_roles?.includes(roleName));
|
118
129
|
|
119
|
-
if (
|
130
|
+
if (
|
131
|
+
!(canMuteOrUnmute || canRemoveRoleFromStage || canRemoveRoleFromRoom) ||
|
132
|
+
peerList.length === 0 ||
|
133
|
+
// if only local peer is present no need to show any options
|
134
|
+
(peerList.length === 1 && peerList[0].isLocal) ||
|
135
|
+
!role
|
136
|
+
) {
|
120
137
|
return null;
|
121
138
|
}
|
122
139
|
|
@@ -165,7 +182,7 @@ export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList
|
|
165
182
|
</Dropdown.Trigger>
|
166
183
|
<Dropdown.Content
|
167
184
|
onClick={e => e.stopPropagation()}
|
168
|
-
css={{ w: 'max-content',
|
185
|
+
css={{ w: 'max-content', bg: '$surface_default', py: 0 }}
|
169
186
|
align="end"
|
170
187
|
>
|
171
188
|
{canRemoveRoleFromStage && (
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import {
|
2
|
+
import { useMedia } from 'react-use';
|
3
|
+
import { VolumeTwoIcon } from '@100mslive/react-icons';
|
4
|
+
import { Button, config, Dialog, IconButton, Text } from '../../..';
|
3
5
|
// @ts-ignore
|
4
6
|
import { DialogContent, DialogRow } from '../../primitives/DialogContent';
|
7
|
+
import { useIsLandscape } from '../../common/hooks';
|
5
8
|
|
6
9
|
export function HLSAutoplayBlockedPrompt({
|
7
10
|
open,
|
@@ -10,6 +13,33 @@ export function HLSAutoplayBlockedPrompt({
|
|
10
13
|
open: boolean;
|
11
14
|
unblockAutoPlay: () => Promise<void>;
|
12
15
|
}) {
|
16
|
+
const isLandscape = useIsLandscape();
|
17
|
+
const isMobile = useMedia(config.media.md);
|
18
|
+
if ((isMobile || isLandscape) && open) {
|
19
|
+
return (
|
20
|
+
<IconButton
|
21
|
+
css={{
|
22
|
+
border: '1px solid white',
|
23
|
+
bg: 'white',
|
24
|
+
color: '#000',
|
25
|
+
r: '$2',
|
26
|
+
}}
|
27
|
+
onClick={async () => await unblockAutoPlay()}
|
28
|
+
>
|
29
|
+
<VolumeTwoIcon width="32" height="32" />
|
30
|
+
<Text
|
31
|
+
variant="body1"
|
32
|
+
css={{
|
33
|
+
fontWeight: '$semiBold',
|
34
|
+
px: '$2',
|
35
|
+
color: '#000',
|
36
|
+
}}
|
37
|
+
>
|
38
|
+
Tap To Unmute
|
39
|
+
</Text>
|
40
|
+
</IconButton>
|
41
|
+
);
|
42
|
+
}
|
13
43
|
return (
|
14
44
|
<Dialog.Root
|
15
45
|
open={open}
|
@@ -1,7 +1,11 @@
|
|
1
1
|
import React, { forwardRef } from 'react';
|
2
|
-
import {
|
2
|
+
import { useMedia } from 'react-use';
|
3
|
+
import { config, Flex } from '../../../';
|
4
|
+
import { useIsLandscape } from '../../common/hooks';
|
3
5
|
|
4
6
|
export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
|
7
|
+
const isLandscape = useIsLandscape();
|
8
|
+
const isMobile = useMedia(config.media.md);
|
5
9
|
return (
|
6
10
|
<Flex
|
7
11
|
data-testid="hms-video"
|
@@ -36,6 +40,8 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
|
|
36
40
|
minHeight: '0',
|
37
41
|
objectFit: 'contain',
|
38
42
|
width: 'inherit',
|
43
|
+
height: isLandscape || isMobile ? '100%' : '',
|
44
|
+
position: isLandscape || isMobile ? 'absolute' : '',
|
39
45
|
}}
|
40
46
|
ref={videoRef}
|
41
47
|
playsInline
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import React, { MouseEvent } from 'react';
|
2
|
+
import { PauseIcon, PlayIcon } from '@100mslive/react-icons';
|
3
|
+
import { IconButton, Tooltip } from '../../..';
|
4
|
+
import { useHMSPlayerContext } from './PlayerContext';
|
5
|
+
|
6
|
+
export const PlayPauseButton = ({
|
7
|
+
isPaused,
|
8
|
+
width = 20,
|
9
|
+
height = 20,
|
10
|
+
}: {
|
11
|
+
isPaused: boolean;
|
12
|
+
width: number;
|
13
|
+
height: number;
|
14
|
+
}) => {
|
15
|
+
const { hlsPlayer } = useHMSPlayerContext();
|
16
|
+
const onClick = async (event: MouseEvent) => {
|
17
|
+
event?.stopPropagation();
|
18
|
+
isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause();
|
19
|
+
};
|
20
|
+
return (
|
21
|
+
<Tooltip title={isPaused ? 'Play' : 'Pause'} side="top">
|
22
|
+
<IconButton onClick={onClick} data-testid="play_pause_btn">
|
23
|
+
{isPaused ? <PlayIcon width={width} height={height} /> : <PauseIcon width={width} height={height} />}
|
24
|
+
</IconButton>
|
25
|
+
</Tooltip>
|
26
|
+
);
|
27
|
+
};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import React, { MouseEventHandler } from 'react';
|
2
|
+
import { IconButton, Tooltip } from '../../..';
|
3
|
+
|
4
|
+
export const SeekControls = ({
|
5
|
+
title,
|
6
|
+
onClick,
|
7
|
+
children,
|
8
|
+
css,
|
9
|
+
}: {
|
10
|
+
title: string;
|
11
|
+
onClick?: MouseEventHandler<HTMLButtonElement>;
|
12
|
+
css: any;
|
13
|
+
children: React.ReactNode;
|
14
|
+
}) => {
|
15
|
+
return (
|
16
|
+
<Tooltip title={title} side="top">
|
17
|
+
<IconButton onClick={onClick} data-testid="backward_forward_arrow_btn" css={css}>
|
18
|
+
{children}
|
19
|
+
</IconButton>
|
20
|
+
</Tooltip>
|
21
|
+
);
|
22
|
+
};
|
@@ -3,7 +3,7 @@ import { Box, Flex, Slider } from '../../..';
|
|
3
3
|
import { useHMSPlayerContext } from './PlayerContext';
|
4
4
|
import { getPercentage } from './utils';
|
5
5
|
|
6
|
-
export const VideoProgress = () => {
|
6
|
+
export const VideoProgress = ({ isDvr = true }: { isDvr: boolean }) => {
|
7
7
|
const { hlsPlayer } = useHMSPlayerContext();
|
8
8
|
const [videoProgress, setVideoProgress] = useState<number>(0);
|
9
9
|
const [bufferProgress, setBufferProgress] = useState(0);
|
@@ -48,7 +48,7 @@ export const VideoProgress = () => {
|
|
48
48
|
return null;
|
49
49
|
}
|
50
50
|
return (
|
51
|
-
<Flex align="center" css={{ cursor: 'pointer', h: '$2', alignSelf: 'stretch' }}>
|
51
|
+
<Flex align="center" css={{ cursor: 'pointer', h: '$2', alignSelf: 'stretch', pointerEvents: isDvr ? '' : 'none' }}>
|
52
52
|
<Slider
|
53
53
|
id="video-actual-rest"
|
54
54
|
css={{
|
@@ -56,6 +56,7 @@ export const VideoProgress = () => {
|
|
56
56
|
h: '$2',
|
57
57
|
zIndex: 1,
|
58
58
|
transition: `all .2s ease .5s`,
|
59
|
+
pointerEvents: isDvr ? '' : 'none',
|
59
60
|
}}
|
60
61
|
min={0}
|
61
62
|
max={100}
|
@@ -63,7 +64,7 @@ export const VideoProgress = () => {
|
|
63
64
|
value={[videoProgress]}
|
64
65
|
showTooltip={false}
|
65
66
|
onValueChange={onProgress}
|
66
|
-
thumbStyles={{ w: '$6', h: '$6' }}
|
67
|
+
thumbStyles={{ w: '$6', h: '$6', display: isDvr ? '' : 'none' }}
|
67
68
|
/>
|
68
69
|
<Box
|
69
70
|
id="video-buffer"
|
@@ -5,7 +5,7 @@ import { useHMSPlayerContext } from './PlayerContext';
|
|
5
5
|
|
6
6
|
export const VolumeControl = () => {
|
7
7
|
const { hlsPlayer } = useHMSPlayerContext();
|
8
|
-
const [volume, setVolume] = useState(hlsPlayer?.volume
|
8
|
+
const [volume, setVolume] = useState(hlsPlayer?.volume ?? 100);
|
9
9
|
const [showSlider, setShowSlider] = useState(false);
|
10
10
|
|
11
11
|
return (
|
@@ -2,14 +2,15 @@
|
|
2
2
|
import { LeftControls, RightControls, VideoControls } from './Controls';
|
3
3
|
// @ts-ignore
|
4
4
|
import { HMSVideo } from './HMSVideo';
|
5
|
-
import {
|
5
|
+
import { PlayPauseButton } from './PlayPauseButton';
|
6
|
+
import { SeekControls } from './SeekControls';
|
6
7
|
import { VideoProgress } from './VideoProgress';
|
7
8
|
import { VideoTime } from './VideoTime';
|
8
9
|
import { VolumeControl } from './VolumeControl';
|
9
10
|
|
10
11
|
export const HMSVideoPlayer = {
|
11
12
|
Root: HMSVideo,
|
12
|
-
|
13
|
+
PlayPauseButton: PlayPauseButton,
|
13
14
|
Progress: VideoProgress,
|
14
15
|
Duration: VideoTime,
|
15
16
|
Volume: VolumeControl,
|
@@ -18,4 +19,5 @@ export const HMSVideoPlayer = {
|
|
18
19
|
Left: LeftControls,
|
19
20
|
Right: RightControls,
|
20
21
|
},
|
22
|
+
Seeker: SeekControls,
|
21
23
|
};
|
@@ -42,7 +42,7 @@ export const LiveStatus = () => {
|
|
42
42
|
setLiveTime(Date.now() - timeStamp.getTime());
|
43
43
|
}
|
44
44
|
}, 1000);
|
45
|
-
}, [hlsState?.running, hlsState?.variants]);
|
45
|
+
}, [hlsState?.running, hlsState?.variants, screenType]);
|
46
46
|
|
47
47
|
useEffect(() => {
|
48
48
|
if (hlsState?.running) {
|
@@ -5,6 +5,7 @@ import {
|
|
5
5
|
DefaultConferencingScreen_Elements,
|
6
6
|
HLSLiveStreamingScreen_Elements,
|
7
7
|
} from '@100mslive/types-prebuilt';
|
8
|
+
import { match } from 'ts-pattern';
|
8
9
|
import { selectAppData, selectLocalPeerID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
9
10
|
import { BrbIcon, CheckIcon, HamburgerMenuIcon, InfoIcon, PipIcon, SettingsIcon } from '@100mslive/react-icons';
|
10
11
|
import { Checkbox, Dropdown, Flex, Text, Tooltip } from '../../../..';
|
@@ -143,41 +144,46 @@ export const DesktopOptions = ({
|
|
143
144
|
Settings
|
144
145
|
</Text>
|
145
146
|
</Dropdown.Item>
|
147
|
+
{match({ screenType, isSupported: HMSHLSPlayer.isSupported() })
|
148
|
+
.with({ screenType: 'hls_live_streaming', isSupported: false }, () => null)
|
149
|
+
.with({ screenType: 'hls_live_streaming', isSupported: true }, () => {
|
150
|
+
return (
|
151
|
+
<Dropdown.Item
|
152
|
+
onClick={() => hmsActions.setAppData(APP_DATA.hlsStats, !enablHlsStats)}
|
153
|
+
data-testid="hls_stats"
|
154
|
+
>
|
155
|
+
<Checkbox.Root
|
156
|
+
css={{ margin: '$2' }}
|
157
|
+
checked={enablHlsStats}
|
158
|
+
onCheckedChange={() => hmsActions.setAppData(APP_DATA.hlsStats, !enablHlsStats)}
|
159
|
+
>
|
160
|
+
<Checkbox.Indicator>
|
161
|
+
<CheckIcon width={16} height={16} />
|
162
|
+
</Checkbox.Indicator>
|
163
|
+
</Checkbox.Root>
|
164
|
+
<Flex justify="between" css={{ width: '100%' }}>
|
165
|
+
<Text variant="sm" css={{ ml: '$4' }}>
|
166
|
+
Show HLS Stats
|
167
|
+
</Text>
|
146
168
|
|
147
|
-
|
148
|
-
|
169
|
+
<Text variant="sm" css={{ ml: '$4' }}>
|
170
|
+
{`${isMacOS ? '⌘' : 'ctrl'} + ]`}
|
171
|
+
</Text>
|
172
|
+
</Flex>
|
173
|
+
</Dropdown.Item>
|
174
|
+
);
|
175
|
+
})
|
176
|
+
.otherwise(() => (
|
149
177
|
<Dropdown.Item
|
150
|
-
onClick={() =>
|
151
|
-
data-testid="
|
178
|
+
onClick={() => updateState(MODALS.STATS_FOR_NERDS, true)}
|
179
|
+
data-testid="stats_for_nerds_btn"
|
152
180
|
>
|
153
|
-
<
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
>
|
158
|
-
<Checkbox.Indicator>
|
159
|
-
<CheckIcon width={16} height={16} />
|
160
|
-
</Checkbox.Indicator>
|
161
|
-
</Checkbox.Root>
|
162
|
-
<Flex justify="between" css={{ width: '100%' }}>
|
163
|
-
<Text variant="sm" css={{ ml: '$4' }}>
|
164
|
-
Show HLS Stats
|
165
|
-
</Text>
|
166
|
-
|
167
|
-
<Text variant="sm" css={{ ml: '$4' }}>
|
168
|
-
{`${isMacOS ? '⌘' : 'ctrl'} + ]`}
|
169
|
-
</Text>
|
170
|
-
</Flex>
|
181
|
+
<InfoIcon />
|
182
|
+
<Text variant="sm" css={{ ml: '$4' }}>
|
183
|
+
Stats for Nerds
|
184
|
+
</Text>
|
171
185
|
</Dropdown.Item>
|
172
|
-
)
|
173
|
-
) : (
|
174
|
-
<Dropdown.Item onClick={() => updateState(MODALS.STATS_FOR_NERDS, true)} data-testid="stats_for_nreds_btn">
|
175
|
-
<InfoIcon />
|
176
|
-
<Text variant="sm" css={{ ml: '$4' }}>
|
177
|
-
Stats for Nerds
|
178
|
-
</Text>
|
179
|
-
</Dropdown.Item>
|
180
|
-
)}
|
186
|
+
))}
|
181
187
|
</Dropdown.Content>
|
182
188
|
</Dropdown.Root>
|
183
189
|
{openModals.has(MODALS.BULK_ROLE_CHANGE) && (
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import React, { useRef, useState } from 'react';
|
2
2
|
import { useClickAway } from 'react-use';
|
3
3
|
import { ConferencingScreen, DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
|
4
|
+
import { match } from 'ts-pattern';
|
4
5
|
import {
|
5
6
|
selectIsConnectedToRoom,
|
6
7
|
selectPeerCount,
|
@@ -287,11 +288,10 @@ export const MwebOptions = ({
|
|
287
288
|
>
|
288
289
|
{isRecordingLoading ? <Loading /> : <RecordIcon />}
|
289
290
|
<ActionTile.Title>
|
290
|
-
{isBrowserRecordingOn
|
291
|
-
|
292
|
-
:
|
293
|
-
|
294
|
-
: 'Start Recording'}
|
291
|
+
{match({ isBrowserRecordingOn, isRecordingLoading })
|
292
|
+
.with({ isBrowserRecordingOn: true, isRecordingLoading: false }, () => 'Recording On')
|
293
|
+
.with({ isRecordingLoading: true }, () => 'Starting Recording')
|
294
|
+
.with({ isRecordingLoading: false }, () => 'Start Recording')}
|
295
295
|
</ActionTile.Title>
|
296
296
|
</ActionTile.Root>
|
297
297
|
) : null}
|
@@ -28,12 +28,12 @@ export const HandRaisedNotifications = () => {
|
|
28
28
|
}
|
29
29
|
|
30
30
|
// Don't show toast message in case of local peer.
|
31
|
-
if (roomState !== HMSRoomState.Connected || notification.data.isLocal || !
|
31
|
+
if (roomState !== HMSRoomState.Connected || notification.data.isLocal || !isSubscribing) {
|
32
32
|
return;
|
33
33
|
}
|
34
34
|
const hasPeerHandRaised = vanillaStore.getState(selectHasPeerHandRaised(notification.data.id));
|
35
35
|
if (hasPeerHandRaised) {
|
36
|
-
ToastBatcher.showToast({ notification, type: 'RAISE_HAND' });
|
36
|
+
ToastBatcher.showToast({ notification, type: on_stage_exp ? 'RAISE_HAND_HLS' : 'RAISE_HAND' });
|
37
37
|
console.debug('Metadata updated', notification.data);
|
38
38
|
}
|
39
39
|
}, [isSubscribing, notification, on_stage_exp, roomState, vanillaStore]);
|
@@ -49,7 +49,7 @@ export const PeerNotifications = () => {
|
|
49
49
|
}
|
50
50
|
|
51
51
|
ToastBatcher.showToast({ notification });
|
52
|
-
}, [notification, isPeerJoinSubscribed, isPeerLeftSubscribed]);
|
52
|
+
}, [notification, isPeerJoinSubscribed, isPeerLeftSubscribed, selectedPeer.id, setPeerSelector]);
|
53
53
|
|
54
54
|
return null;
|
55
55
|
};
|