@100mslive/roomkit-react 0.1.12-alpha.0 → 0.1.13-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-J2MIS3H2.js → HLSView-AIPLCDXY.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/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/Theme/stitches.config.d.ts +226 -226
- package/dist/{chunk-OYSYEA6R.js → chunk-5DCII2TP.js} +2248 -1269
- package/dist/chunk-5DCII2TP.js.map +7 -0
- package/dist/index.cjs.js +2943 -1902
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +819 -313
- package/dist/meta.esbuild.json +826 -320
- package/package.json +8 -8
- 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 +4 -4
- package/src/Prebuilt/components/Chat/Chat.jsx +51 -73
- package/src/Prebuilt/components/Chat/ChatBody.jsx +219 -48
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +50 -6
- package/src/Prebuilt/components/Chat/ChatStates.jsx +66 -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 +118 -0
- package/src/Prebuilt/components/Footer/Footer.tsx +4 -7
- package/src/Prebuilt/components/Header/common.jsx +1 -1
- package/src/Prebuilt/components/Preview/PreviewJoin.tsx +6 -8
- 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 +20 -0
- package/src/Prebuilt/components/VirtualBackground/VBCollection.tsx +4 -4
- package/src/Prebuilt/components/VirtualBackground/{VBPicker.jsx → VBPicker.tsx} +27 -18
- 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 +76 -0
- package/src/Prebuilt/layouts/SidePane.tsx +1 -1
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +30 -2
- 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/src/Theme/stitches.config.ts +1 -2
- package/dist/chunk-OYSYEA6R.js.map +0 -7
- package/src/Prebuilt/components/hooks/useSetPinnedMessage.js +0 -38
- package/src/Prebuilt/services/tokenService.js +0 -49
- /package/dist/{HLSView-J2MIS3H2.js.map → HLSView-AIPLCDXY.js.map} +0 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
2
|
+
import { useSwipeable } from 'react-swipeable';
|
3
|
+
import { useMedia } from 'react-use';
|
4
|
+
import { selectPermissions, 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 permissions = useHMSStore(selectPermissions);
|
20
|
+
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
21
|
+
const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0);
|
22
|
+
const isMobile = useMedia(cssConfig.media.md);
|
23
|
+
|
24
|
+
const [hideOverflow, setHideOverflow] = useState(false);
|
25
|
+
|
26
|
+
const formattedPinnedMessage = hideOverflow
|
27
|
+
? `${pinnedMessages?.[pinnedMessageIndex]?.text.slice(0, PINNED_MESSAGE_LENGTH)}... `
|
28
|
+
: pinnedMessages?.[pinnedMessageIndex]?.text;
|
29
|
+
|
30
|
+
const pinnedMessageRef = useRef(null);
|
31
|
+
const showPreviousPinnedMessage = () => {
|
32
|
+
const previousIndex = Math.max(pinnedMessageIndex - 1, 0);
|
33
|
+
setHideOverflow(pinnedMessages[previousIndex].text.length > PINNED_MESSAGE_LENGTH);
|
34
|
+
setPinnedMessageIndex(previousIndex);
|
35
|
+
};
|
36
|
+
|
37
|
+
const showNextPinnedMessage = () => {
|
38
|
+
const nextIndex = Math.min(pinnedMessageIndex + 1, pinnedMessages.length - 1);
|
39
|
+
setHideOverflow(pinnedMessages[nextIndex].text.length > PINNED_MESSAGE_LENGTH);
|
40
|
+
setPinnedMessageIndex(nextIndex);
|
41
|
+
};
|
42
|
+
|
43
|
+
const swipeHandlers = useSwipeable({
|
44
|
+
onSwipedUp: () => showNextPinnedMessage(),
|
45
|
+
onSwipedDown: () => showPreviousPinnedMessage(),
|
46
|
+
});
|
47
|
+
|
48
|
+
useEffect(() => {
|
49
|
+
setHideOverflow(
|
50
|
+
!!(
|
51
|
+
pinnedMessages?.[pinnedMessageIndex]?.text?.length &&
|
52
|
+
pinnedMessages?.[pinnedMessageIndex]?.text.length > PINNED_MESSAGE_LENGTH
|
53
|
+
),
|
54
|
+
);
|
55
|
+
}, [pinnedMessageIndex, pinnedMessages]);
|
56
|
+
|
57
|
+
return pinnedMessages?.[pinnedMessageIndex]?.text ? (
|
58
|
+
<Flex ref={pinnedMessageRef} align="center" css={{ w: '100%', gap: '$4' }}>
|
59
|
+
<Flex
|
60
|
+
title={pinnedMessages[pinnedMessageIndex].text}
|
61
|
+
css={{
|
62
|
+
p: '$4',
|
63
|
+
color: '$on_surface_medium',
|
64
|
+
bg: isMobile ? 'rgba(0, 0, 0, 0.64)' : '$surface_default',
|
65
|
+
r: '$1',
|
66
|
+
gap: '$4',
|
67
|
+
mb: '$8',
|
68
|
+
mt: '$8',
|
69
|
+
flexGrow: 1,
|
70
|
+
}}
|
71
|
+
align="center"
|
72
|
+
justify="between"
|
73
|
+
>
|
74
|
+
<Navigation
|
75
|
+
index={pinnedMessageIndex}
|
76
|
+
total={pinnedMessages.length}
|
77
|
+
showPrevious={showPreviousPinnedMessage}
|
78
|
+
showNext={showNextPinnedMessage}
|
79
|
+
isMobile={isMobile}
|
80
|
+
/>
|
81
|
+
<PinIcon />
|
82
|
+
|
83
|
+
<Box
|
84
|
+
css={{
|
85
|
+
w: '100%',
|
86
|
+
maxHeight: '$18',
|
87
|
+
overflowY: 'auto',
|
88
|
+
overflowX: 'hidden',
|
89
|
+
wordBreak: 'break-word',
|
90
|
+
'& p span': {
|
91
|
+
color: '$primary_default',
|
92
|
+
},
|
93
|
+
}}
|
94
|
+
>
|
95
|
+
<Text variant="sm" css={{ color: '$on_surface_medium' }} {...swipeHandlers}>
|
96
|
+
<AnnotisedMessage message={formattedPinnedMessage} />
|
97
|
+
{hideOverflow ? (
|
98
|
+
<span style={{ cursor: 'pointer' }} onClick={() => setHideOverflow(false)}>
|
99
|
+
See more
|
100
|
+
</span>
|
101
|
+
) : null}
|
102
|
+
</Text>
|
103
|
+
</Box>
|
104
|
+
{permissions?.removeOthers && (
|
105
|
+
<Flex
|
106
|
+
onClick={() => {
|
107
|
+
clearPinnedMessage(pinnedMessageIndex);
|
108
|
+
setPinnedMessageIndex(Math.max(0, pinnedMessageIndex - 1));
|
109
|
+
}}
|
110
|
+
css={{ cursor: 'pointer', color: '$on_surface_medium', '&:hover': { color: '$on_surface_high' } }}
|
111
|
+
>
|
112
|
+
<CrossIcon />
|
113
|
+
</Flex>
|
114
|
+
)}
|
115
|
+
</Flex>
|
116
|
+
</Flex>
|
117
|
+
) : null;
|
118
|
+
};
|
@@ -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;
|
@@ -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}
|
@@ -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,6 +1,7 @@
|
|
1
1
|
import React, { useCallback } from 'react';
|
2
2
|
import { selectPeerByID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
3
3
|
import {
|
4
|
+
ChatIcon,
|
4
5
|
ChatUnreadIcon,
|
5
6
|
ConnectivityIcon,
|
6
7
|
HandIcon,
|
@@ -58,6 +59,7 @@ const HandRaiseAction = React.forwardRef(({ id = '', isSingleHandRaise = true },
|
|
58
59
|
</Button>
|
59
60
|
);
|
60
61
|
});
|
62
|
+
|
61
63
|
export const ToastConfig = {
|
62
64
|
PEER_LIST: {
|
63
65
|
single: function (notification) {
|
@@ -144,6 +146,24 @@ export const ToastConfig = {
|
|
144
146
|
};
|
145
147
|
},
|
146
148
|
},
|
149
|
+
CHAT_PAUSED: {
|
150
|
+
single: notification => {
|
151
|
+
return {
|
152
|
+
title: `Chat paused by ${notification.data?.name}`,
|
153
|
+
icon: <ChatIcon />,
|
154
|
+
action: <ChatAction />,
|
155
|
+
};
|
156
|
+
},
|
157
|
+
},
|
158
|
+
CHAT_RESUMED: {
|
159
|
+
single: notification => {
|
160
|
+
return {
|
161
|
+
title: `Chat resumed by ${notification.data?.name}`,
|
162
|
+
icon: <ChatUnreadIcon />,
|
163
|
+
action: <ChatAction />,
|
164
|
+
};
|
165
|
+
},
|
166
|
+
},
|
147
167
|
RECONNECTED: {
|
148
168
|
single: () => {
|
149
169
|
return {
|
@@ -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,14 @@ 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
|
|
43
51
|
// 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
52
|
const showVideoTile = isVideoOn && isLargeRoom && roomState !== HMSRoomState.Preview;
|
45
53
|
|
46
54
|
const clearVBState = () => {
|
47
|
-
setBackground(
|
48
|
-
setBackgroundType(
|
55
|
+
setBackground(HMSVirtualBackgroundTypes.NONE);
|
56
|
+
setBackgroundType(HMSVirtualBackgroundTypes.NONE);
|
49
57
|
};
|
50
58
|
|
51
59
|
useEffect(() => {
|
@@ -62,7 +70,7 @@ export const VBPicker = () => {
|
|
62
70
|
|
63
71
|
async function disableEffects() {
|
64
72
|
if (vbPlugin) {
|
65
|
-
vbPlugin.setBackground(
|
73
|
+
vbPlugin.setBackground(HMSVirtualBackgroundTypes.NONE, HMSVirtualBackgroundTypes.NONE);
|
66
74
|
clearVBState();
|
67
75
|
}
|
68
76
|
}
|
@@ -75,18 +83,18 @@ export const VBPicker = () => {
|
|
75
83
|
img.alt = 'VB';
|
76
84
|
img.src = mediaURL;
|
77
85
|
try {
|
78
|
-
await vbPlugin.setBackground(img,
|
86
|
+
await vbPlugin.setBackground(img, HMSVirtualBackgroundTypes.IMAGE);
|
79
87
|
} catch (e) {
|
80
88
|
console.error(e);
|
81
89
|
if (retries++ < MAX_RETRIES) {
|
82
|
-
await vbPlugin.setBackground(img,
|
90
|
+
await vbPlugin.setBackground(img, HMSVirtualBackgroundTypes.IMAGE);
|
83
91
|
}
|
84
92
|
}
|
85
93
|
} else if (blurPower) {
|
86
|
-
await vbPlugin.setBackground(
|
94
|
+
await vbPlugin.setBackground(HMSVirtualBackgroundTypes.BLUR, HMSVirtualBackgroundTypes.BLUR);
|
87
95
|
}
|
88
|
-
setBackground(mediaURL ||
|
89
|
-
setBackgroundType(mediaURL ?
|
96
|
+
setBackground(mediaURL || HMSVirtualBackgroundTypes.BLUR);
|
97
|
+
setBackgroundType(mediaURL ? HMSVirtualBackgroundTypes.IMAGE : HMSVirtualBackgroundTypes.BLUR);
|
90
98
|
if (role && !addedPluginToVideoTrack.current) {
|
91
99
|
await hmsActions.addPluginToVideoTrack(vbPlugin, Math.floor(role.publishParams.video.frameRate / 2));
|
92
100
|
addedPluginToVideoTrack.current = true;
|
@@ -136,29 +144,30 @@ export const VBPicker = () => {
|
|
136
144
|
{
|
137
145
|
title: 'No effect',
|
138
146
|
icon: <CrossCircleIcon style={iconDims} />,
|
139
|
-
type:
|
147
|
+
type: HMSVirtualBackgroundTypes.NONE,
|
140
148
|
onClick: async () => await disableEffects(),
|
141
149
|
},
|
142
150
|
{
|
143
151
|
title: 'Blur',
|
144
152
|
icon: <BlurPersonHighIcon style={iconDims} />,
|
145
|
-
type:
|
153
|
+
type: HMSVirtualBackgroundTypes.BLUR,
|
146
154
|
onClick: async () => await addPlugin({ blurPower: 0.5 }),
|
147
155
|
},
|
148
156
|
]}
|
149
|
-
activeBackgroundType={backgroundType ||
|
150
|
-
|
157
|
+
activeBackgroundType={backgroundType || HMSVirtualBackgroundTypes.NONE}
|
158
|
+
// @ts-ignore
|
159
|
+
activeBackground={vbPlugin.background?.src || vbPlugin.background || HMSVirtualBackgroundTypes.NONE}
|
151
160
|
/>
|
152
161
|
|
153
162
|
<VBCollection
|
154
163
|
title="Backgrounds"
|
155
|
-
options={
|
156
|
-
type:
|
164
|
+
options={mediaList.map(mediaURL => ({
|
165
|
+
type: HMSVirtualBackgroundTypes.IMAGE,
|
157
166
|
mediaURL,
|
158
167
|
onClick: async () => await addPlugin({ mediaURL }),
|
159
168
|
}))}
|
160
|
-
activeBackgroundType={backgroundType ||
|
161
|
-
activeBackground={background?.src || background ||
|
169
|
+
activeBackgroundType={backgroundType || HMSVirtualBackgroundTypes.NONE}
|
170
|
+
activeBackground={background?.src || background || HMSVirtualBackgroundTypes.NONE}
|
162
171
|
/>
|
163
172
|
</Box>
|
164
173
|
);
|
@@ -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',
|
@@ -42,7 +42,16 @@ export const useAutoStartStreaming = () => {
|
|
42
42
|
streamStartedRef.current = false;
|
43
43
|
setHLSStarted(false);
|
44
44
|
}
|
45
|
-
}, [
|
45
|
+
}, [
|
46
|
+
hmsActions,
|
47
|
+
isHLSRunning,
|
48
|
+
isHLSStarted,
|
49
|
+
setHLSStarted,
|
50
|
+
showStreamingUI,
|
51
|
+
isRTMPRunning,
|
52
|
+
isHLSRecordingOn,
|
53
|
+
isBrowserRecordingOn,
|
54
|
+
]);
|
46
55
|
|
47
56
|
useEffect(() => {
|
48
57
|
if (!isHLSStarted && !isHLSRunning) {
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { useCallback } from 'react';
|
2
|
+
import { useHMSActions } from '@100mslive/react-sdk';
|
3
|
+
// @ts-ignore
|
4
|
+
import { ToastManager } from '../Toast/ToastManager';
|
5
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
6
|
+
|
7
|
+
export const useChatBlacklist = (
|
8
|
+
sessionStoreKey: SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST | SESSION_STORE_KEY.CHAT_PEER_BLACKLIST,
|
9
|
+
) => {
|
10
|
+
const hmsActions = useHMSActions();
|
11
|
+
|
12
|
+
const blacklistItem = useCallback(
|
13
|
+
async (blacklistedIDs: string[], blacklistID: string) =>
|
14
|
+
await hmsActions.sessionStore
|
15
|
+
.set(sessionStoreKey, [...blacklistedIDs, blacklistID])
|
16
|
+
.catch(err => ToastManager.addToast({ title: err.description })),
|
17
|
+
[hmsActions, sessionStoreKey],
|
18
|
+
);
|
19
|
+
|
20
|
+
return { blacklistItem };
|
21
|
+
};
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { useCallback } from 'react';
|
2
|
+
import { HMSMessage, selectPeerNameByID, useHMSActions, useHMSVanillaStore } from '@100mslive/react-sdk';
|
3
|
+
// @ts-ignore
|
4
|
+
import { ToastManager } from '../Toast/ToastManager';
|
5
|
+
// @ts-ignore
|
6
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
7
|
+
|
8
|
+
type PinnedMessage = {
|
9
|
+
text: string;
|
10
|
+
id: string;
|
11
|
+
authorId: string;
|
12
|
+
pinnedBy: string;
|
13
|
+
};
|
14
|
+
|
15
|
+
/**
|
16
|
+
* set pinned chat message by updating the session store
|
17
|
+
*/
|
18
|
+
export const useSetPinnedMessages = () => {
|
19
|
+
const hmsActions = useHMSActions();
|
20
|
+
const vanillaStore = useHMSVanillaStore();
|
21
|
+
// const pinnedMessages: PinnedMessage[] = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
22
|
+
|
23
|
+
const setPinnedMessages = useCallback(
|
24
|
+
async (pinnedMessages: PinnedMessage[] = [], message: HMSMessage, pinnedBy: string) => {
|
25
|
+
const peerName = vanillaStore.getState(selectPeerNameByID(message?.sender)) || message?.senderName;
|
26
|
+
const newPinnedMessage = { text: '', id: message.id, pinnedBy, authorId: message?.sender || '' };
|
27
|
+
|
28
|
+
if (message && peerName) {
|
29
|
+
newPinnedMessage['text'] = `${peerName}: ${message.message}`;
|
30
|
+
} else if (message) {
|
31
|
+
newPinnedMessage['text'] = message.message;
|
32
|
+
}
|
33
|
+
|
34
|
+
if (newPinnedMessage && !pinnedMessages.find(pinnedMessage => pinnedMessage.id === newPinnedMessage.id)) {
|
35
|
+
await hmsActions.sessionStore
|
36
|
+
.set(SESSION_STORE_KEY.PINNED_MESSAGES, [...pinnedMessages, newPinnedMessage].slice(-3)) // Limiting to maximum of 3 messages - FIFO
|
37
|
+
.catch(err => ToastManager.addToast({ title: err.description }));
|
38
|
+
}
|
39
|
+
},
|
40
|
+
[hmsActions, vanillaStore],
|
41
|
+
);
|
42
|
+
|
43
|
+
const removePinnedMessage = useCallback(
|
44
|
+
async (pinnedMessages: PinnedMessage[] = [], indexToRemove: number) => {
|
45
|
+
if (pinnedMessages[indexToRemove]) {
|
46
|
+
await hmsActions.sessionStore
|
47
|
+
.set(
|
48
|
+
SESSION_STORE_KEY.PINNED_MESSAGES,
|
49
|
+
pinnedMessages.filter((_, index: number) => index !== indexToRemove),
|
50
|
+
)
|
51
|
+
.catch(err => ToastManager.addToast({ title: err.description }));
|
52
|
+
}
|
53
|
+
},
|
54
|
+
[hmsActions],
|
55
|
+
);
|
56
|
+
|
57
|
+
const unpinBlacklistedMessages = useCallback(
|
58
|
+
async (
|
59
|
+
pinnedMessages: PinnedMessage[] = [],
|
60
|
+
blacklistedPeerIDSet: Set<string>,
|
61
|
+
blacklistedMessageIDSet: Set<string>,
|
62
|
+
) => {
|
63
|
+
const filteredPinnedMessages = pinnedMessages?.filter(
|
64
|
+
pinnedMessage =>
|
65
|
+
!blacklistedMessageIDSet?.has(pinnedMessage.id) && !blacklistedPeerIDSet.has(pinnedMessage.authorId),
|
66
|
+
);
|
67
|
+
|
68
|
+
await hmsActions.sessionStore
|
69
|
+
.set(SESSION_STORE_KEY.PINNED_MESSAGES, filteredPinnedMessages)
|
70
|
+
.catch(err => ToastManager.addToast({ title: err.description }));
|
71
|
+
},
|
72
|
+
[hmsActions],
|
73
|
+
);
|
74
|
+
|
75
|
+
return { setPinnedMessages, removePinnedMessage, unpinBlacklistedMessages };
|
76
|
+
};
|
@@ -41,7 +41,7 @@ const SidePane = ({
|
|
41
41
|
ViewComponent = <SidePaneTabs screenType={screenType} hideControls={hideControls} active={sidepane} />;
|
42
42
|
}
|
43
43
|
if (sidepane === SIDE_PANE_OPTIONS.VB) {
|
44
|
-
ViewComponent = <VBPicker />;
|
44
|
+
ViewComponent = <VBPicker {...elements.virtual_background} />;
|
45
45
|
}
|
46
46
|
|
47
47
|
useEffect(() => {
|