@100mslive/roomkit-react 0.1.12 → 0.1.13
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-PWVM4OIP.js → HLSView-IENE4HRP.js} +2 -2
- package/dist/Prebuilt/App.d.ts +0 -2
- package/dist/Prebuilt/AppContext.d.ts +0 -2
- package/dist/Prebuilt/common/constants.d.ts +110 -0
- package/dist/Prebuilt/components/AppData/AppData.d.ts +2 -0
- package/dist/Prebuilt/components/Chat/MwebChatOption.d.ts +7 -0
- package/dist/Prebuilt/components/Chat/Navigation.d.ts +8 -0
- package/dist/Prebuilt/components/Chat/PinnedMessage.d.ts +4 -0
- package/dist/Prebuilt/components/Footer/Footer.d.ts +3 -2
- package/dist/Prebuilt/components/Notifications/ChatNotifications.d.ts +2 -0
- package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +2 -1
- package/dist/Prebuilt/components/VirtualBackground/VBCollection.d.ts +2 -1
- package/dist/Prebuilt/components/VirtualBackground/VBPicker.d.ts +3 -0
- package/dist/Prebuilt/components/VirtualBackground/constants.d.ts +0 -6
- package/dist/Prebuilt/components/hooks/useChatBlacklist.d.ts +4 -0
- package/dist/Prebuilt/components/hooks/useSetPinnedMessages.d.ts +16 -0
- package/dist/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.d.ts +3 -2
- package/dist/{chunk-WREKGNP6.js → chunk-U4AB6X6M.js} +2178 -1148
- package/dist/chunk-U4AB6X6M.js.map +7 -0
- package/dist/index.cjs.js +2746 -1638
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +803 -208
- package/dist/meta.esbuild.json +812 -217
- package/package.json +8 -7
- package/src/Prebuilt/App.tsx +3 -14
- package/src/Prebuilt/AppContext.tsx +0 -2
- package/src/Prebuilt/common/{constants.js → constants.ts} +22 -20
- package/src/Prebuilt/components/AppData/{AppData.jsx → AppData.tsx} +8 -22
- package/src/Prebuilt/components/AppData/useUISettings.js +0 -4
- package/src/Prebuilt/components/AuthToken.jsx +15 -5
- package/src/Prebuilt/components/Chat/Chat.jsx +49 -73
- package/src/Prebuilt/components/Chat/ChatBody.jsx +241 -51
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +56 -6
- package/src/Prebuilt/components/Chat/ChatStates.jsx +68 -0
- package/src/Prebuilt/components/Chat/MwebChatOption.tsx +24 -0
- package/src/Prebuilt/components/Chat/Navigation.tsx +60 -0
- package/src/Prebuilt/components/Chat/PinnedMessage.tsx +116 -0
- package/src/Prebuilt/components/Footer/Footer.tsx +4 -7
- package/src/Prebuilt/components/Header/common.jsx +1 -1
- package/src/Prebuilt/components/Notifications/ChatNotifications.tsx +34 -0
- package/src/Prebuilt/components/Notifications/Notifications.tsx +2 -0
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +6 -4
- package/src/Prebuilt/components/Polls/Voting/TimedVoting.jsx +3 -2
- package/src/Prebuilt/components/Polls/common/VoteCount.jsx +6 -4
- package/src/Prebuilt/components/Preview/PreviewJoin.tsx +7 -9
- package/src/Prebuilt/components/RoleChangeRequest/RoleChangeRequestModal.tsx +4 -1
- package/src/Prebuilt/components/Settings/DeviceSettings.jsx +1 -1
- package/src/Prebuilt/components/SidePaneTabs.tsx +3 -2
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +1 -0
- package/src/Prebuilt/components/VirtualBackground/VBCollection.tsx +4 -4
- package/src/Prebuilt/components/VirtualBackground/{VBPicker.jsx → VBPicker.tsx} +64 -44
- package/src/Prebuilt/components/VirtualBackground/constants.ts +0 -8
- package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +10 -1
- package/src/Prebuilt/components/hooks/useChatBlacklist.ts +21 -0
- package/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +75 -0
- package/src/Prebuilt/components/hooks/useUserPreferences.jsx +1 -0
- package/src/Prebuilt/layouts/SidePane.tsx +1 -1
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +16 -8
- package/src/Prebuilt/plugins/whiteboard/PusherCommunicationProvider.js +1 -1
- package/src/Prebuilt/plugins/whiteboard/README.md +1 -1
- package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
- package/src/Prebuilt/provider/roomLayoutProvider/constants/index.ts +12 -1
- package/src/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.ts +5 -1
- package/dist/chunk-WREKGNP6.js.map +0 -7
- package/src/Prebuilt/components/hooks/useSetPinnedMessage.js +0 -38
- package/src/Prebuilt/services/tokenService.js +0 -49
- /package/dist/{HLSView-PWVM4OIP.js.map → HLSView-IENE4HRP.js.map} +0 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
2
|
+
import { useSwipeable } from 'react-swipeable';
|
3
|
+
import { useMedia } from 'react-use';
|
4
|
+
import { selectSessionStore, useHMSStore } from '@100mslive/react-sdk';
|
5
|
+
import { CrossIcon, PinIcon } from '@100mslive/react-icons';
|
6
|
+
import { Box, Flex } from '../../../Layout';
|
7
|
+
import { Text } from '../../../Text';
|
8
|
+
import { config as cssConfig } from '../../../Theme';
|
9
|
+
// @ts-ignore
|
10
|
+
import { AnnotisedMessage } from './ChatBody';
|
11
|
+
// @ts-ignore
|
12
|
+
import { Navigation } from './Navigation';
|
13
|
+
// @ts-ignore
|
14
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
15
|
+
|
16
|
+
const PINNED_MESSAGE_LENGTH = 75;
|
17
|
+
|
18
|
+
export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (index: number) => void }) => {
|
19
|
+
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
20
|
+
const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0);
|
21
|
+
const isMobile = useMedia(cssConfig.media.md);
|
22
|
+
|
23
|
+
const [hideOverflow, setHideOverflow] = useState(false);
|
24
|
+
const canOverflow = pinnedMessages?.[pinnedMessageIndex]?.text?.length > PINNED_MESSAGE_LENGTH || false;
|
25
|
+
const formattedPinnedMessage = hideOverflow
|
26
|
+
? `${pinnedMessages?.[pinnedMessageIndex]?.text.slice(0, PINNED_MESSAGE_LENGTH)}... `
|
27
|
+
: pinnedMessages?.[pinnedMessageIndex]?.text;
|
28
|
+
|
29
|
+
const pinnedMessageRef = useRef(null);
|
30
|
+
const showPreviousPinnedMessage = () => {
|
31
|
+
const previousIndex = Math.max(pinnedMessageIndex - 1, 0);
|
32
|
+
setHideOverflow(pinnedMessages[previousIndex].text.length > PINNED_MESSAGE_LENGTH);
|
33
|
+
setPinnedMessageIndex(previousIndex);
|
34
|
+
};
|
35
|
+
|
36
|
+
const showNextPinnedMessage = () => {
|
37
|
+
const nextIndex = Math.min(pinnedMessageIndex + 1, pinnedMessages.length - 1);
|
38
|
+
setHideOverflow(pinnedMessages[nextIndex].text.length > PINNED_MESSAGE_LENGTH);
|
39
|
+
setPinnedMessageIndex(nextIndex);
|
40
|
+
};
|
41
|
+
|
42
|
+
const swipeHandlers = useSwipeable({
|
43
|
+
onSwipedUp: () => showNextPinnedMessage(),
|
44
|
+
onSwipedDown: () => showPreviousPinnedMessage(),
|
45
|
+
});
|
46
|
+
|
47
|
+
useEffect(() => {
|
48
|
+
setHideOverflow(
|
49
|
+
!!(
|
50
|
+
pinnedMessages?.[pinnedMessageIndex]?.text?.length &&
|
51
|
+
pinnedMessages?.[pinnedMessageIndex]?.text.length > PINNED_MESSAGE_LENGTH
|
52
|
+
),
|
53
|
+
);
|
54
|
+
}, [pinnedMessageIndex, pinnedMessages]);
|
55
|
+
|
56
|
+
return pinnedMessages?.[pinnedMessageIndex]?.text ? (
|
57
|
+
<Flex ref={pinnedMessageRef} align="center" css={{ w: '100%', gap: '$4' }}>
|
58
|
+
<Flex
|
59
|
+
title={pinnedMessages[pinnedMessageIndex].text}
|
60
|
+
css={{
|
61
|
+
p: '$4',
|
62
|
+
color: '$on_surface_medium',
|
63
|
+
bg: isMobile ? 'rgba(0, 0, 0, 0.64)' : '$surface_default',
|
64
|
+
r: '$1',
|
65
|
+
gap: '$4',
|
66
|
+
mb: '$8',
|
67
|
+
mt: '$8',
|
68
|
+
flexGrow: 1,
|
69
|
+
}}
|
70
|
+
align="center"
|
71
|
+
justify="between"
|
72
|
+
>
|
73
|
+
<Navigation
|
74
|
+
index={pinnedMessageIndex}
|
75
|
+
total={pinnedMessages.length}
|
76
|
+
showPrevious={showPreviousPinnedMessage}
|
77
|
+
showNext={showNextPinnedMessage}
|
78
|
+
isMobile={isMobile}
|
79
|
+
/>
|
80
|
+
<PinIcon />
|
81
|
+
|
82
|
+
<Box
|
83
|
+
css={{
|
84
|
+
w: '100%',
|
85
|
+
maxHeight: '$18',
|
86
|
+
overflowY: 'auto',
|
87
|
+
overflowX: 'hidden',
|
88
|
+
wordBreak: 'break-word',
|
89
|
+
'& p span': {
|
90
|
+
color: '$primary_default',
|
91
|
+
},
|
92
|
+
}}
|
93
|
+
>
|
94
|
+
<Text variant="sm" css={{ color: '$on_surface_medium' }} {...swipeHandlers}>
|
95
|
+
<AnnotisedMessage message={formattedPinnedMessage} />
|
96
|
+
{canOverflow ? (
|
97
|
+
<span style={{ cursor: 'pointer' }} onClick={() => setHideOverflow(prev => !prev)}>
|
98
|
+
$nbsp;{hideOverflow ? 'See more' : 'Collapse'}
|
99
|
+
</span>
|
100
|
+
) : null}
|
101
|
+
</Text>
|
102
|
+
</Box>
|
103
|
+
|
104
|
+
<Flex
|
105
|
+
onClick={() => {
|
106
|
+
clearPinnedMessage(pinnedMessageIndex);
|
107
|
+
setPinnedMessageIndex(Math.max(0, pinnedMessageIndex - 1));
|
108
|
+
}}
|
109
|
+
css={{ cursor: 'pointer', color: '$on_surface_medium', '&:hover': { color: '$on_surface_high' } }}
|
110
|
+
>
|
111
|
+
<CrossIcon />
|
112
|
+
</Flex>
|
113
|
+
</Flex>
|
114
|
+
</Flex>
|
115
|
+
) : null;
|
116
|
+
};
|
@@ -1,10 +1,6 @@
|
|
1
1
|
import React, { useEffect } from 'react';
|
2
2
|
import { useMedia } from 'react-use';
|
3
|
-
import {
|
4
|
-
ConferencingScreen,
|
5
|
-
DefaultConferencingScreen_Elements,
|
6
|
-
HLSLiveStreamingScreen_Elements,
|
7
|
-
} from '@100mslive/types-prebuilt';
|
3
|
+
import { ConferencingScreen } from '@100mslive/types-prebuilt';
|
8
4
|
import { Chat_ChatState } from '@100mslive/types-prebuilt/elements/chat';
|
9
5
|
import { useAVToggle } from '@100mslive/react-sdk';
|
10
6
|
import { config as cssConfig, Footer as AppFooter } from '../../..';
|
@@ -27,6 +23,7 @@ import { ChatToggle } from './ChatToggle';
|
|
27
23
|
// @ts-ignore: No implicit Any
|
28
24
|
import { ParticipantCount } from './ParticipantList';
|
29
25
|
import { PollsToggle } from './PollsToggle';
|
26
|
+
import { ConferencingScreenElements } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
30
27
|
// @ts-ignore: No implicit Any
|
31
28
|
import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
|
32
29
|
// @ts-ignore: No implicit Any
|
@@ -39,7 +36,7 @@ export const Footer = ({
|
|
39
36
|
elements,
|
40
37
|
}: {
|
41
38
|
screenType: keyof ConferencingScreen;
|
42
|
-
elements:
|
39
|
+
elements: ConferencingScreenElements;
|
43
40
|
}) => {
|
44
41
|
const isMobile = useMedia(cssConfig.media.md);
|
45
42
|
const isOverlayChat = !!elements?.chat?.is_overlay;
|
@@ -82,7 +79,7 @@ export const Footer = ({
|
|
82
79
|
>
|
83
80
|
{isMobile ? <LeaveRoom screenType={screenType} /> : null}
|
84
81
|
<AudioVideoToggle />
|
85
|
-
{isMobile
|
82
|
+
{!isMobile && elements.virtual_background ? <VBToggle /> : null}
|
86
83
|
</AppFooter.Left>
|
87
84
|
<AppFooter.Center
|
88
85
|
css={{
|
@@ -61,7 +61,7 @@ export const AudioActions = () => {
|
|
61
61
|
const { allDevices, selectedDeviceIDs, updateDevice } = useDevices();
|
62
62
|
|
63
63
|
// don't show speaker selector where the API is not supported, and use
|
64
|
-
// a generic word("Audio") for Mic. In some cases(Chrome Android for
|
64
|
+
// a generic word("Audio") for Mic. In some cases(Chrome Android for example) this changes both mic and speaker keeping them in sync.
|
65
65
|
const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype;
|
66
66
|
const { audioInput, audioOutput } = allDevices;
|
67
67
|
let availableAudioDevices = audioInput;
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React, { useEffect } from 'react';
|
2
|
+
import { v4 as uuid } from 'uuid';
|
3
|
+
import { selectLocalPeerID, selectSessionStore, useHMSStore } from '@100mslive/react-sdk';
|
4
|
+
import { ChatIcon, ChatUnreadIcon } from '@100mslive/react-icons';
|
5
|
+
// @ts-ignore
|
6
|
+
import { ToastManager } from '../Toast/ToastManager';
|
7
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
8
|
+
|
9
|
+
const NOTIFICATION_TIME_DIFFERENCE = 5000;
|
10
|
+
|
11
|
+
export const ChatNotifications = () => {
|
12
|
+
const chatState = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE));
|
13
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
14
|
+
|
15
|
+
useEffect(() => {
|
16
|
+
if (!chatState || chatState.updatedBy?.peerId === localPeerId) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const showToast = Date.now() - chatState.updatedAt < NOTIFICATION_TIME_DIFFERENCE;
|
21
|
+
|
22
|
+
if (!showToast) {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
|
26
|
+
const notification = {
|
27
|
+
id: uuid(),
|
28
|
+
icon: chatState.enabled ? <ChatUnreadIcon /> : <ChatIcon />,
|
29
|
+
title: `Chat ${chatState.enabled ? 'resumed' : 'paused'} by ${chatState.updatedBy?.userName}`,
|
30
|
+
};
|
31
|
+
ToastManager.addToast(notification);
|
32
|
+
}, [chatState]);
|
33
|
+
return <></>;
|
34
|
+
};
|
@@ -20,6 +20,7 @@ import { ToastBatcher } from '../Toast/ToastBatcher';
|
|
20
20
|
// @ts-ignore: No implicit Any
|
21
21
|
import { ToastManager } from '../Toast/ToastManager';
|
22
22
|
import { AutoplayBlockedModal } from './AutoplayBlockedModal';
|
23
|
+
import { ChatNotifications } from './ChatNotifications';
|
23
24
|
import { InitErrorModal } from './InitErrorModal';
|
24
25
|
import { PeerNotifications } from './PeerNotifications';
|
25
26
|
import { PermissionErrorModal } from './PermissionErrorModal';
|
@@ -186,6 +187,7 @@ export function Notifications() {
|
|
186
187
|
<AutoplayBlockedModal />
|
187
188
|
<PermissionErrorModal />
|
188
189
|
<InitErrorModal />
|
190
|
+
<ChatNotifications />
|
189
191
|
</>
|
190
192
|
);
|
191
193
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// @ts-check
|
2
2
|
import React, { useCallback, useMemo, useState } from 'react';
|
3
|
-
import {
|
3
|
+
import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
4
4
|
import { ChevronLeftIcon, ChevronRightIcon } from '@100mslive/react-icons';
|
5
5
|
import { Box, Button, Flex, IconButton, Input, styled, Text } from '../../../../';
|
6
6
|
import { checkCorrectAnswer } from '../../../common/utils';
|
@@ -38,9 +38,11 @@ export const QuestionCard = ({
|
|
38
38
|
rolesThatCanViewResponses,
|
39
39
|
}) => {
|
40
40
|
const actions = useHMSActions();
|
41
|
-
const
|
42
|
-
const localPeerResponse = responses?.find(
|
43
|
-
|
41
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
42
|
+
const localPeerResponse = responses?.find(
|
43
|
+
response => response.peer?.peerid === localPeer?.id || response.peer?.userid === localPeer?.customerUserId,
|
44
|
+
);
|
45
|
+
const isLocalPeerCreator = localPeer?.id === startedBy;
|
44
46
|
const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
|
45
47
|
const roleCanViewResponse =
|
46
48
|
!rolesThatCanViewResponses ||
|
@@ -8,8 +8,9 @@ import { QuestionCard } from './QuestionCard';
|
|
8
8
|
* @returns
|
9
9
|
*/
|
10
10
|
export const TimedView = ({ poll }) => {
|
11
|
-
|
12
|
-
const
|
11
|
+
// backend question index starts at 1
|
12
|
+
const [currentIndex, setCurrentIndex] = useState(1);
|
13
|
+
const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
|
13
14
|
if (!activeQuestion) {
|
14
15
|
return null;
|
15
16
|
}
|
@@ -19,10 +19,12 @@ export const VoteCount = ({ isQuiz, voteCount, isCorrectAnswer }) => {
|
|
19
19
|
{isCorrectAnswer ? 'Correct' : 'Incorrect'}
|
20
20
|
</Text>
|
21
21
|
)}
|
22
|
-
|
23
|
-
{
|
24
|
-
|
25
|
-
|
22
|
+
{voteCount ? (
|
23
|
+
<Text variant="sm" css={{ color: '$on_surface_medium' }}>
|
24
|
+
{voteCount}
|
25
|
+
{voteCount === 1 ? 'vote' : 'votes'}
|
26
|
+
</Text>
|
27
|
+
) : null}
|
26
28
|
</Flex>
|
27
29
|
);
|
28
30
|
};
|
@@ -19,7 +19,6 @@ import { useHMSPrebuiltContext } from '../../AppContext';
|
|
19
19
|
// @ts-ignore: No implicit Any
|
20
20
|
import IconButton from '../../IconButton';
|
21
21
|
import SidePane from '../../layouts/SidePane';
|
22
|
-
import { useRoomLayout } from '../../provider/roomLayoutProvider';
|
23
22
|
// @ts-ignore: No implicit Any
|
24
23
|
import { AudioVideoToggle } from '../AudioVideoToggle';
|
25
24
|
// @ts-ignore: No implicit Any
|
@@ -36,13 +35,13 @@ import SettingsModal from '../Settings/SettingsModal';
|
|
36
35
|
import { VBToggle } from '../VirtualBackground/VBToggle';
|
37
36
|
// @ts-ignore: No implicit Any
|
38
37
|
import PreviewForm from './PreviewForm';
|
38
|
+
import { useRoomLayoutPreviewScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
39
39
|
// @ts-ignore: No implicit Any
|
40
40
|
import { useAuthToken, useUISettings } from '../AppData/useUISettings';
|
41
41
|
// @ts-ignore: No implicit Any
|
42
42
|
import { defaultPreviewPreference, UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
|
43
43
|
// @ts-ignore: No implicit Any
|
44
44
|
import { calculateAvatarAndAttribBoxSize, getFormattedCount } from '../../common/utils';
|
45
|
-
// @ts-ignore: No implicit Any
|
46
45
|
import { UI_SETTINGS } from '../../common/constants';
|
47
46
|
|
48
47
|
const getParticipantChipContent = (peerCount = 0) => {
|
@@ -111,9 +110,8 @@ const PreviewJoin = ({
|
|
111
110
|
});
|
112
111
|
join();
|
113
112
|
}, [join, name, setPreviewPreference]);
|
114
|
-
const
|
115
|
-
|
116
|
-
const { preview_header: previewHeader = {} } = roomLayout?.screens?.preview?.default?.elements || {};
|
113
|
+
const { elements = {} } = useRoomLayoutPreviewScreen();
|
114
|
+
const { preview_header: previewHeader = {}, virtual_background } = elements || {};
|
117
115
|
const aspectRatio = useLocalTileAspectRatio();
|
118
116
|
useEffect(() => {
|
119
117
|
if (authToken) {
|
@@ -177,7 +175,7 @@ const PreviewJoin = ({
|
|
177
175
|
</Flex>
|
178
176
|
) : null}
|
179
177
|
<Box css={{ w: '100%', maxWidth: `${Math.max(aspectRatio, 1) * 360}px` }}>
|
180
|
-
<PreviewControls hideSettings={!toggleVideo && !toggleAudio} />
|
178
|
+
<PreviewControls hideSettings={!toggleVideo && !toggleAudio} vbEnabled={!!virtual_background} />
|
181
179
|
<PreviewForm
|
182
180
|
name={name}
|
183
181
|
onChange={setName}
|
@@ -188,7 +186,7 @@ const PreviewJoin = ({
|
|
188
186
|
/>
|
189
187
|
</Box>
|
190
188
|
</Container>
|
191
|
-
<Box css={{ position: 'absolute', right: '0', top: 0, height: '100%' }}>
|
189
|
+
<Box css={{ position: 'absolute', right: '0', top: 0, height: '100%', overflow: 'hidden' }}>
|
192
190
|
<SidePane screenType="default" />
|
193
191
|
</Box>
|
194
192
|
</Flex>
|
@@ -266,7 +264,7 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
|
|
266
264
|
);
|
267
265
|
};
|
268
266
|
|
269
|
-
export const PreviewControls = ({ hideSettings }: { hideSettings: boolean }) => {
|
267
|
+
export const PreviewControls = ({ hideSettings, vbEnabled }: { hideSettings: boolean; vbEnabled: boolean }) => {
|
270
268
|
const isMobile = useMedia(cssConfig.media.md);
|
271
269
|
|
272
270
|
return (
|
@@ -279,7 +277,7 @@ export const PreviewControls = ({ hideSettings }: { hideSettings: boolean }) =>
|
|
279
277
|
>
|
280
278
|
<Flex css={{ gap: '$4' }}>
|
281
279
|
<AudioVideoToggle />
|
282
|
-
{!isMobile ? <VBToggle /> : null}
|
280
|
+
{!isMobile && vbEnabled ? <VBToggle /> : null}
|
283
281
|
</Flex>
|
284
282
|
{!hideSettings ? <PreviewSettings /> : null}
|
285
283
|
</Flex>
|
@@ -11,6 +11,7 @@ import { Flex, Text } from '../../..';
|
|
11
11
|
// @ts-ignore: No implicit Any
|
12
12
|
import { PreviewControls, PreviewTile } from '../Preview/PreviewJoin';
|
13
13
|
import { RequestPrompt } from './RequestPrompt';
|
14
|
+
import { useRoomLayoutPreviewScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
14
15
|
// @ts-ignore: No implicit Any
|
15
16
|
import { useMyMetadata } from '../hooks/useMetadata';
|
16
17
|
// @ts-ignore: No implicit Any
|
@@ -23,6 +24,8 @@ export const RoleChangeRequestModal = () => {
|
|
23
24
|
const roleChangeRequest = useHMSStore(selectRoleChangeRequest);
|
24
25
|
const name = useHMSStore(selectLocalPeerName);
|
25
26
|
const { sendEvent } = useCustomEvent({ type: ROLE_CHANGE_DECLINED });
|
27
|
+
const { elements = {} } = useRoomLayoutPreviewScreen();
|
28
|
+
const { virtual_background } = elements || {};
|
26
29
|
|
27
30
|
useEffect(() => {
|
28
31
|
if (!roleChangeRequest?.role) {
|
@@ -61,7 +64,7 @@ export const RoleChangeRequestModal = () => {
|
|
61
64
|
>
|
62
65
|
<PreviewTile name={name || ''} />
|
63
66
|
|
64
|
-
<PreviewControls hideSettings={true} />
|
67
|
+
<PreviewControls hideSettings={true} vbEnabled={!!virtual_background} />
|
65
68
|
</Flex>
|
66
69
|
</>
|
67
70
|
);
|
@@ -29,7 +29,7 @@ const Settings = ({ setHide }) => {
|
|
29
29
|
const videoTrackId = useHMSStore(selectLocalVideoTrackID);
|
30
30
|
const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
|
31
31
|
// don't show speaker selector where the API is not supported, and use
|
32
|
-
// a generic word("Audio") for Mic. In some cases(Chrome Android for
|
32
|
+
// a generic word("Audio") for Mic. In some cases(Chrome Android for example) this changes both mic and speaker keeping them in sync.
|
33
33
|
const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype;
|
34
34
|
const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo);
|
35
35
|
const trackSelector = selectVideoTrackByID(videoTrackId);
|
@@ -50,6 +50,7 @@ export const SidePaneTabs = React.memo<{
|
|
50
50
|
const [activeRole, setActiveRole] = useState('');
|
51
51
|
const peerCount = useHMSStore(selectPeerCount);
|
52
52
|
const { elements } = useRoomLayoutConferencingScreen();
|
53
|
+
const chat_title = elements?.chat?.chat_title || 'Chat';
|
53
54
|
const showChat = !!elements?.chat;
|
54
55
|
const showParticipants = !!elements?.participant_list;
|
55
56
|
const hideTabs = !(showChat && showParticipants);
|
@@ -109,7 +110,7 @@ export const SidePaneTabs = React.memo<{
|
|
109
110
|
<>
|
110
111
|
<Text variant="sm" css={{ fontWeight: '$semiBold', p: '$4', c: '$on_surface_high', pr: '$12' }}>
|
111
112
|
{showChat ? (
|
112
|
-
|
113
|
+
chat_title
|
113
114
|
) : (
|
114
115
|
<span>
|
115
116
|
Participants <ParticipantCount count={peerCount} />
|
@@ -141,7 +142,7 @@ export const SidePaneTabs = React.memo<{
|
|
141
142
|
color: activeTab !== SIDE_PANE_OPTIONS.CHAT ? '$on_surface_low' : '$on_surface_high',
|
142
143
|
}}
|
143
144
|
>
|
144
|
-
|
145
|
+
{chat_title}
|
145
146
|
</Tabs.Trigger>
|
146
147
|
<Tabs.Trigger
|
147
148
|
value={SIDE_PANE_OPTIONS.PARTICIPANTS}
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import React from 'react';
|
2
|
+
import { HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background';
|
2
3
|
import { Box } from '../../../Layout';
|
3
4
|
import { Text } from '../../../Text';
|
4
5
|
import { VBOption } from './VBOption';
|
5
|
-
import { VB_EFFECT } from './constants';
|
6
6
|
|
7
7
|
export const VBCollection = ({
|
8
8
|
options,
|
9
9
|
title,
|
10
|
-
activeBackgroundType =
|
10
|
+
activeBackgroundType = HMSVirtualBackgroundTypes.NONE,
|
11
11
|
activeBackground = '',
|
12
12
|
}: {
|
13
13
|
options: {
|
@@ -19,7 +19,7 @@ export const VBCollection = ({
|
|
19
19
|
}[];
|
20
20
|
title: string;
|
21
21
|
activeBackground: HTMLImageElement | string;
|
22
|
-
activeBackgroundType:
|
22
|
+
activeBackgroundType: HMSVirtualBackgroundTypes;
|
23
23
|
}) => {
|
24
24
|
if (options.length === 0) {
|
25
25
|
return null;
|
@@ -35,7 +35,7 @@ export const VBCollection = ({
|
|
35
35
|
key={option?.mediaURL || option?.title}
|
36
36
|
{...option}
|
37
37
|
isActive={
|
38
|
-
([
|
38
|
+
([HMSVirtualBackgroundTypes.NONE, HMSVirtualBackgroundTypes.BLUR].includes(activeBackgroundType) &&
|
39
39
|
option.type === activeBackgroundType) ||
|
40
40
|
activeBackground === option?.mediaURL
|
41
41
|
}
|
@@ -1,4 +1,6 @@
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
2
|
+
import { HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background';
|
3
|
+
import { VirtualBackground, VirtualBackgroundMedia } from '@100mslive/types-prebuilt/elements/virtual_background';
|
2
4
|
import {
|
3
5
|
HMSRoomState,
|
4
6
|
selectIsLargeRoom,
|
@@ -15,22 +17,27 @@ import { BlurPersonHighIcon, CloseIcon, CrossCircleIcon } from '@100mslive/react
|
|
15
17
|
import { Box, Flex, Video } from '../../../index';
|
16
18
|
import { Text } from '../../../Text';
|
17
19
|
import { VBCollection } from './VBCollection';
|
20
|
+
// @ts-ignore
|
18
21
|
import { useSidepaneToggle } from '../AppData/useSidepane';
|
22
|
+
// @ts-ignore
|
19
23
|
import { useUISettings } from '../AppData/useUISettings';
|
24
|
+
// @ts-ignore
|
20
25
|
import { SIDE_PANE_OPTIONS, UI_SETTINGS } from '../../common/constants';
|
21
|
-
import { defaultMedia,
|
26
|
+
import { defaultMedia, vbPlugin } from './constants';
|
22
27
|
|
23
28
|
const iconDims = { height: '40px', width: '40px' };
|
24
29
|
const MAX_RETRIES = 2;
|
25
30
|
|
26
|
-
export const VBPicker = () => {
|
31
|
+
export const VBPicker = ({ background_media = [] }: VirtualBackground = {}) => {
|
27
32
|
const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB);
|
28
33
|
const hmsActions = useHMSActions();
|
29
34
|
const role = useHMSStore(selectLocalPeerRole);
|
30
35
|
const [isVBSupported, setIsVBSupported] = useState(false);
|
31
36
|
const localPeerVideoTrackID = useHMSStore(selectLocalVideoTrackID);
|
32
37
|
const localPeer = useHMSStore(selectLocalPeer);
|
38
|
+
// @ts-ignore
|
33
39
|
const [background, setBackground] = useState(vbPlugin.background);
|
40
|
+
// @ts-ignore
|
34
41
|
const [backgroundType, setBackgroundType] = useState(vbPlugin.backgroundType);
|
35
42
|
const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
|
36
43
|
const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo);
|
@@ -39,13 +46,15 @@ export const VBPicker = () => {
|
|
39
46
|
const roomState = useHMSStore(selectRoomState);
|
40
47
|
const isLargeRoom = useHMSStore(selectIsLargeRoom);
|
41
48
|
const addedPluginToVideoTrack = useRef(false);
|
49
|
+
const mediaList = [...background_media.map((media: VirtualBackgroundMedia) => media?.url), ...defaultMedia];
|
42
50
|
|
51
|
+
const inPreview = roomState === HMSRoomState.Preview;
|
43
52
|
// Hidden in preview as the effect will be visible in the preview tile. Needed inside the room because the peer might not be on-screen
|
44
|
-
const showVideoTile = isVideoOn && isLargeRoom &&
|
53
|
+
const showVideoTile = isVideoOn && isLargeRoom && !inPreview;
|
45
54
|
|
46
55
|
const clearVBState = () => {
|
47
|
-
setBackground(
|
48
|
-
setBackgroundType(
|
56
|
+
setBackground(HMSVirtualBackgroundTypes.NONE);
|
57
|
+
setBackgroundType(HMSVirtualBackgroundTypes.NONE);
|
49
58
|
};
|
50
59
|
|
51
60
|
useEffect(() => {
|
@@ -62,7 +71,7 @@ export const VBPicker = () => {
|
|
62
71
|
|
63
72
|
async function disableEffects() {
|
64
73
|
if (vbPlugin) {
|
65
|
-
vbPlugin.setBackground(
|
74
|
+
vbPlugin.setBackground(HMSVirtualBackgroundTypes.NONE, HMSVirtualBackgroundTypes.NONE);
|
66
75
|
clearVBState();
|
67
76
|
}
|
68
77
|
}
|
@@ -75,18 +84,18 @@ export const VBPicker = () => {
|
|
75
84
|
img.alt = 'VB';
|
76
85
|
img.src = mediaURL;
|
77
86
|
try {
|
78
|
-
await vbPlugin.setBackground(img,
|
87
|
+
await vbPlugin.setBackground(img, HMSVirtualBackgroundTypes.IMAGE);
|
79
88
|
} catch (e) {
|
80
89
|
console.error(e);
|
81
90
|
if (retries++ < MAX_RETRIES) {
|
82
|
-
await vbPlugin.setBackground(img,
|
91
|
+
await vbPlugin.setBackground(img, HMSVirtualBackgroundTypes.IMAGE);
|
83
92
|
}
|
84
93
|
}
|
85
94
|
} else if (blurPower) {
|
86
|
-
await vbPlugin.setBackground(
|
95
|
+
await vbPlugin.setBackground(HMSVirtualBackgroundTypes.BLUR, HMSVirtualBackgroundTypes.BLUR);
|
87
96
|
}
|
88
|
-
setBackground(mediaURL ||
|
89
|
-
setBackgroundType(mediaURL ?
|
97
|
+
setBackground(mediaURL || HMSVirtualBackgroundTypes.BLUR);
|
98
|
+
setBackgroundType(mediaURL ? HMSVirtualBackgroundTypes.IMAGE : HMSVirtualBackgroundTypes.BLUR);
|
90
99
|
if (role && !addedPluginToVideoTrack.current) {
|
91
100
|
await hmsActions.addPluginToVideoTrack(vbPlugin, Math.floor(role.publishParams.video.frameRate / 2));
|
92
101
|
addedPluginToVideoTrack.current = true;
|
@@ -108,8 +117,8 @@ export const VBPicker = () => {
|
|
108
117
|
}
|
109
118
|
|
110
119
|
return (
|
111
|
-
<
|
112
|
-
<Flex align="center" justify="between" css={{ w: '100%',
|
120
|
+
<Flex css={{ pr: '$6', size: '100%' }} direction="column">
|
121
|
+
<Flex align="center" justify="between" css={{ w: '100%', background: '$surface_dim', pb: '$4' }}>
|
113
122
|
<Text variant="h6" css={{ color: '$on_surface_high' }}>
|
114
123
|
Virtual Background
|
115
124
|
</Text>
|
@@ -126,40 +135,51 @@ export const VBPicker = () => {
|
|
126
135
|
mirror={track?.facingMode !== 'environment' && mirrorLocalVideo}
|
127
136
|
trackId={localPeer?.videoTrack}
|
128
137
|
data-testid="preview_tile"
|
129
|
-
css={{ width: '100%', height: '16rem'
|
138
|
+
css={{ width: '100%', height: '16rem' }}
|
130
139
|
/>
|
131
140
|
) : null}
|
132
141
|
|
133
|
-
<
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
142
|
+
<Box
|
143
|
+
css={{
|
144
|
+
mt: '$4',
|
145
|
+
overflowY: 'auto',
|
146
|
+
flex: '1 1 0',
|
147
|
+
mr: '-$10',
|
148
|
+
pr: '$10',
|
149
|
+
}}
|
150
|
+
>
|
151
|
+
<VBCollection
|
152
|
+
title="Effects"
|
153
|
+
options={[
|
154
|
+
{
|
155
|
+
title: 'No effect',
|
156
|
+
icon: <CrossCircleIcon style={iconDims} />,
|
157
|
+
type: HMSVirtualBackgroundTypes.NONE,
|
158
|
+
onClick: async () => await disableEffects(),
|
159
|
+
},
|
160
|
+
{
|
161
|
+
title: 'Blur',
|
162
|
+
icon: <BlurPersonHighIcon style={iconDims} />,
|
163
|
+
type: HMSVirtualBackgroundTypes.BLUR,
|
164
|
+
onClick: async () => await addPlugin({ blurPower: 0.5 }),
|
165
|
+
},
|
166
|
+
]}
|
167
|
+
activeBackgroundType={backgroundType || HMSVirtualBackgroundTypes.NONE}
|
168
|
+
// @ts-ignore
|
169
|
+
activeBackground={vbPlugin.background?.src || vbPlugin.background || HMSVirtualBackgroundTypes.NONE}
|
170
|
+
/>
|
152
171
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
172
|
+
<VBCollection
|
173
|
+
title="Backgrounds"
|
174
|
+
options={mediaList.map(mediaURL => ({
|
175
|
+
type: HMSVirtualBackgroundTypes.IMAGE,
|
176
|
+
mediaURL,
|
177
|
+
onClick: async () => await addPlugin({ mediaURL }),
|
178
|
+
}))}
|
179
|
+
activeBackgroundType={backgroundType || HMSVirtualBackgroundTypes.NONE}
|
180
|
+
activeBackground={background?.src || background || HMSVirtualBackgroundTypes.NONE}
|
181
|
+
/>
|
182
|
+
</Box>
|
183
|
+
</Flex>
|
164
184
|
);
|
165
185
|
};
|
@@ -1,13 +1,5 @@
|
|
1
1
|
import { HMSVBPlugin, HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background';
|
2
2
|
|
3
|
-
// Will support all media, setting to image here to test with current plugin interface
|
4
|
-
export const VB_EFFECT = {
|
5
|
-
BLUR: 'blur',
|
6
|
-
BEAUTIFY: 'BEAUTIFY',
|
7
|
-
NONE: 'none',
|
8
|
-
MEDIA: 'image',
|
9
|
-
};
|
10
|
-
|
11
3
|
export const defaultMedia = [
|
12
4
|
'https://assets.100ms.live/webapp/vb-mini/vb-1.jpg',
|
13
5
|
'https://assets.100ms.live/webapp/vb-mini/vb-2.jpg',
|