@100mslive/roomkit-react 0.1.6-alpha.0 → 0.1.6-alpha.1
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-PY2FKWX3.js → HLSView-HNVYG5VE.js} +208 -118
- package/dist/HLSView-HNVYG5VE.js.map +7 -0
- package/dist/Prebuilt/AppContext.d.ts +1 -1
- package/dist/Prebuilt/components/Chat/ChatFooter.d.ts +7 -0
- package/dist/Prebuilt/components/Connection/ConnectionIndicator.d.ts +6 -0
- package/dist/Prebuilt/components/Connection/TileConnection.d.ts +10 -0
- package/dist/Prebuilt/components/Footer/ChatToggle.d.ts +4 -0
- package/dist/Prebuilt/components/Footer/RoleAccordion.d.ts +14 -0
- package/dist/Prebuilt/components/Footer/RoleOptions.d.ts +6 -0
- package/dist/Prebuilt/components/Header/StreamActions.d.ts +11 -0
- package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +4 -3
- package/dist/Prebuilt/components/Leave/EndSessionContent.d.ts +4 -3
- package/dist/Prebuilt/components/Leave/LeaveCard.d.ts +1 -2
- package/dist/Prebuilt/components/Leave/LeaveSessionContent.d.ts +3 -1
- package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +4 -3
- package/dist/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.d.ts +6 -0
- package/dist/Prebuilt/components/Preview/PreviewContainer.d.ts +3 -0
- package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +16 -0
- package/dist/Prebuilt/components/RoleChangeRequestModal.d.ts +2 -0
- package/dist/Prebuilt/components/SecondaryTiles.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/EqualProminence.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/Grid.d.ts +1 -0
- package/dist/Prebuilt/components/VideoLayouts/GridLayout.d.ts +5 -3
- package/dist/Prebuilt/components/VideoLayouts/ProminenceLayout.d.ts +6 -3
- package/dist/Prebuilt/components/VideoLayouts/RoleProminence.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/ScreenshareLayout.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/interface.d.ts +1 -0
- package/dist/Prebuilt/components/hooks/useAutoStartStreaming.d.ts +1 -0
- package/dist/Prebuilt/components/hooks/useRedirectToLeave.d.ts +3 -0
- package/dist/Prebuilt/components/hooks/useTileLayout.d.ts +2 -1
- package/dist/Prebuilt/components/hooks/useVideoTileLayout.d.ts +2 -0
- package/dist/Prebuilt/layouts/SidePane.d.ts +4 -1
- package/dist/Prebuilt/layouts/VideoStreamingSection.d.ts +2 -1
- package/dist/{VirtualBackground-AYDHYLIZ.js → VirtualBackground-UM2FOUHQ.js} +3 -3
- package/dist/{chunk-E2M2ZSOL.js → chunk-364HP22I.js} +2 -2
- package/dist/{chunk-RXTHJUMZ.js → chunk-LYSAET4G.js} +946 -390
- package/dist/chunk-LYSAET4G.js.map +7 -0
- package/dist/{chunk-GQD2AGWW.js → chunk-POE7H4IE.js} +12 -2
- package/dist/{chunk-GQD2AGWW.js.map → chunk-POE7H4IE.js.map} +2 -2
- package/dist/{conference-V2XZGTKU.js → conference-UWLJHMB2.js} +1116 -1316
- package/dist/conference-UWLJHMB2.js.map +7 -0
- package/dist/index.cjs.js +6080 -5631
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +2 -2
- package/dist/meta.cjs.json +741 -493
- package/dist/meta.esbuild.json +782 -529
- package/package.json +8 -7
- package/src/Prebuilt/App.tsx +10 -21
- package/src/Prebuilt/AppContext.tsx +1 -1
- package/src/Prebuilt/IconButton.jsx +10 -0
- package/src/Prebuilt/common/PeersSorter.ts +1 -1
- package/src/Prebuilt/common/constants.js +1 -2
- package/src/Prebuilt/common/utils.js +1 -1
- package/src/Prebuilt/components/AppData/AppData.jsx +8 -2
- package/src/Prebuilt/components/AppData/useUISettings.js +6 -6
- package/src/Prebuilt/components/AudioVideoToggle.jsx +8 -6
- package/src/Prebuilt/components/Chat/Chat.jsx +23 -6
- package/src/Prebuilt/components/Chat/ChatBody.jsx +20 -21
- package/src/Prebuilt/components/Chat/{ChatFooter.jsx → ChatFooter.tsx} +38 -13
- package/src/Prebuilt/components/Chat/ChatParticipantHeader.jsx +38 -27
- package/src/Prebuilt/components/Chat/useEmojiPickerStyles.js +5 -4
- package/src/Prebuilt/components/Connection/{ConnectionIndicator.jsx → ConnectionIndicator.tsx} +12 -4
- package/src/Prebuilt/components/Connection/{TileConnection.jsx → TileConnection.tsx} +20 -6
- package/src/Prebuilt/components/EmojiReaction.jsx +2 -6
- package/src/Prebuilt/components/Footer/{ChatToggle.jsx → ChatToggle.tsx} +13 -3
- package/src/Prebuilt/components/Footer/Footer.tsx +15 -6
- package/src/Prebuilt/components/Footer/ParticipantList.jsx +15 -47
- package/src/Prebuilt/components/Footer/{RoleAccordion.jsx → RoleAccordion.tsx} +33 -17
- package/src/Prebuilt/components/Footer/RoleOptions.tsx +155 -0
- package/src/Prebuilt/components/FullPageProgress.jsx +3 -3
- package/src/Prebuilt/components/HMSVideo/Controls.jsx +1 -0
- package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +39 -17
- package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +2 -2
- package/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +5 -6
- package/src/Prebuilt/components/HMSVideo/VolumeControl.jsx +1 -1
- package/src/Prebuilt/components/Header/{StreamActions.jsx → StreamActions.tsx} +23 -9
- package/src/Prebuilt/components/Header/common.jsx +5 -2
- package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +6 -1
- package/src/Prebuilt/components/InsetTile.tsx +14 -8
- package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +21 -11
- package/src/Prebuilt/components/Leave/EndSessionContent.tsx +2 -5
- package/src/Prebuilt/components/Leave/LeaveCard.tsx +1 -3
- package/src/Prebuilt/components/Leave/LeaveRoom.tsx +28 -25
- package/src/Prebuilt/components/Leave/LeaveSessionContent.tsx +8 -2
- package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +8 -8
- package/src/Prebuilt/components/MoreSettings/ChangeNameContent.jsx +4 -0
- package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +1 -1
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +9 -23
- package/src/Prebuilt/components/MoreSettings/SplitComponents/{MwebOptions.jsx → MwebOptions.tsx} +88 -27
- package/src/Prebuilt/components/Notifications/Notifications.jsx +30 -21
- package/src/Prebuilt/components/Notifications/ReconnectNotifications.jsx +5 -11
- package/src/Prebuilt/components/Pagination.tsx +14 -12
- package/src/Prebuilt/components/Preview/{PreviewContainer.jsx → PreviewContainer.tsx} +11 -2
- package/src/Prebuilt/components/Preview/PreviewForm.tsx +6 -8
- package/src/Prebuilt/components/Preview/{PreviewJoin.jsx → PreviewJoin.tsx} +43 -19
- package/src/Prebuilt/components/{RoleChangeRequestModal.jsx → RoleChangeRequestModal.tsx} +32 -15
- package/src/Prebuilt/components/ScreenshareTile.jsx +6 -7
- package/src/Prebuilt/components/SecondaryTiles.tsx +12 -10
- package/src/Prebuilt/components/TileMenu/TileMenu.jsx +1 -1
- package/src/Prebuilt/components/TileMenu/TileMenuContent.jsx +14 -10
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +5 -4
- package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +13 -10
- package/src/Prebuilt/components/VideoLayouts/Grid.tsx +36 -34
- package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +33 -15
- package/src/Prebuilt/components/VideoLayouts/ProminenceLayout.tsx +45 -31
- package/src/Prebuilt/components/VideoLayouts/RoleProminence.tsx +12 -9
- package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +25 -9
- package/src/Prebuilt/components/VideoLayouts/interface.ts +1 -0
- package/src/Prebuilt/components/VideoTile.jsx +45 -53
- package/src/Prebuilt/components/conference.jsx +71 -74
- package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +57 -0
- package/src/Prebuilt/components/hooks/useMetadata.jsx +12 -3
- package/src/Prebuilt/components/hooks/useRedirectToLeave.tsx +34 -0
- package/src/Prebuilt/components/hooks/useRoleProminencePeers.tsx +1 -1
- package/src/Prebuilt/components/hooks/useTileLayout.tsx +24 -18
- package/src/Prebuilt/components/hooks/useVideoTileLayout.ts +4 -0
- package/src/Prebuilt/layouts/EmbedView.jsx +1 -11
- package/src/Prebuilt/layouts/HLSView.jsx +152 -82
- package/src/Prebuilt/layouts/SidePane.tsx +15 -3
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +11 -47
- package/src/Prebuilt/plugins/FlyingEmoji.jsx +14 -2
- package/src/Prebuilt/services/FeatureFlags.jsx +0 -1
- package/src/VideoTile/StyledVideoTile.tsx +1 -0
- package/dist/HLSView-PY2FKWX3.js.map +0 -7
- package/dist/chunk-RXTHJUMZ.js.map +0 -7
- package/dist/conference-V2XZGTKU.js.map +0 -7
- package/src/Prebuilt/components/AudioLevel/BeamSpeakerLabelsLogging.jsx +0 -16
- package/src/Prebuilt/components/VideoList.jsx +0 -73
- /package/dist/{VirtualBackground-AYDHYLIZ.js.map → VirtualBackground-UM2FOUHQ.js.map} +0 -0
- /package/dist/{chunk-E2M2ZSOL.js.map → chunk-364HP22I.js.map} +0 -0
|
@@ -1,53 +1,61 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useMeasure } from 'react-use';
|
|
3
3
|
import { FixedSizeList } from 'react-window';
|
|
4
|
+
import { HMSPeer } from '@100mslive/react-sdk';
|
|
4
5
|
import { Accordion } from '../../../Accordion';
|
|
5
6
|
import { Box, Flex } from '../../../Layout';
|
|
7
|
+
import { Text } from '../../../Text';
|
|
8
|
+
// @ts-ignore: No implicit Any
|
|
6
9
|
import { Participant } from './ParticipantList';
|
|
10
|
+
import { RoleOptions } from './RoleOptions';
|
|
11
|
+
// @ts-ignore: No implicit Any
|
|
7
12
|
import { getFormattedCount } from '../../common/utils';
|
|
8
13
|
|
|
9
14
|
const ROW_HEIGHT = 50;
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
interface ItemData {
|
|
17
|
+
peerList: HMSPeer[];
|
|
18
|
+
isConnected: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function itemKey(index: number, data: ItemData) {
|
|
12
22
|
return data.peerList[index].id;
|
|
13
23
|
}
|
|
14
24
|
|
|
15
|
-
const VirtualizedParticipantItem = React.memo(({ index, data }) => {
|
|
16
|
-
return
|
|
17
|
-
<Participant
|
|
18
|
-
key={data.peerList[index].id}
|
|
19
|
-
peer={data.peerList[index]}
|
|
20
|
-
isConnected={data.isConnected}
|
|
21
|
-
setSelectedPeerId={data.setSelectedPeerId}
|
|
22
|
-
/>
|
|
23
|
-
);
|
|
25
|
+
const VirtualizedParticipantItem = React.memo(({ index, data }: { index: number; data: ItemData }) => {
|
|
26
|
+
return <Participant key={data.peerList[index].id} peer={data.peerList[index]} isConnected={data.isConnected} />;
|
|
24
27
|
});
|
|
25
28
|
|
|
26
29
|
export const RoleAccordion = ({
|
|
27
30
|
peerList = [],
|
|
28
31
|
roleName,
|
|
29
|
-
setSelectedPeerId,
|
|
30
32
|
isConnected,
|
|
31
33
|
filter,
|
|
32
34
|
isHandRaisedAccordion = false,
|
|
35
|
+
}: ItemData & {
|
|
36
|
+
roleName: string;
|
|
37
|
+
isHandRaisedAccordion?: boolean;
|
|
38
|
+
filter?: { search: string };
|
|
33
39
|
}) => {
|
|
34
|
-
const [ref, { width }] = useMeasure();
|
|
35
|
-
const height = ROW_HEIGHT * peerList.length;
|
|
40
|
+
const [ref, { width }] = useMeasure<HTMLDivElement>();
|
|
36
41
|
const showAcordion = filter?.search ? peerList.some(peer => peer.name.toLowerCase().includes(filter.search)) : true;
|
|
42
|
+
|
|
37
43
|
if (!showAcordion || (isHandRaisedAccordion && filter?.search) || peerList.length === 0) {
|
|
38
44
|
return null;
|
|
39
45
|
}
|
|
46
|
+
const height = ROW_HEIGHT * peerList.length;
|
|
40
47
|
|
|
41
48
|
return (
|
|
42
|
-
<Flex direction="column" css={{ flexGrow: 1 }} ref={ref}>
|
|
49
|
+
<Flex direction="column" css={{ flexGrow: 1, '&:hover .role_actions': { visibility: 'visible' } }} ref={ref}>
|
|
43
50
|
<Accordion.Root
|
|
44
51
|
type="single"
|
|
45
52
|
collapsible
|
|
46
53
|
defaultValue={roleName}
|
|
47
|
-
css={{ borderRadius: '$
|
|
54
|
+
css={{ borderRadius: '$1', border: '1px solid $border_bright' }}
|
|
48
55
|
>
|
|
49
56
|
<Accordion.Item value={roleName}>
|
|
50
57
|
<Accordion.Header
|
|
58
|
+
iconStyles={{ c: '$on_surface_high' }}
|
|
51
59
|
css={{
|
|
52
60
|
textTransform: 'capitalize',
|
|
53
61
|
p: '$6 $8',
|
|
@@ -56,13 +64,21 @@ export const RoleAccordion = ({
|
|
|
56
64
|
c: '$on_surface_medium',
|
|
57
65
|
}}
|
|
58
66
|
>
|
|
59
|
-
{
|
|
67
|
+
<Flex justify="between" css={{ flexGrow: 1, pr: '$6' }}>
|
|
68
|
+
<Text
|
|
69
|
+
variant="sm"
|
|
70
|
+
css={{ fontWeight: '$semiBold', textTransform: 'capitalize', color: '$on_surface_medium' }}
|
|
71
|
+
>
|
|
72
|
+
{roleName} {`(${getFormattedCount(peerList.length)})`}
|
|
73
|
+
</Text>
|
|
74
|
+
<RoleOptions roleName={roleName} peerList={peerList} />
|
|
75
|
+
</Flex>
|
|
60
76
|
</Accordion.Header>
|
|
61
77
|
<Accordion.Content>
|
|
62
78
|
<Box css={{ borderTop: '1px solid $border_default' }} />
|
|
63
79
|
<FixedSizeList
|
|
64
80
|
itemSize={ROW_HEIGHT}
|
|
65
|
-
itemData={{ peerList, isConnected
|
|
81
|
+
itemData={{ peerList, isConnected }}
|
|
66
82
|
itemKey={itemKey}
|
|
67
83
|
itemCount={peerList.length}
|
|
68
84
|
width={width}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
|
|
3
|
+
import { HMSPeer, selectPermissions, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
|
|
4
|
+
import {
|
|
5
|
+
MicOffIcon,
|
|
6
|
+
MicOnIcon,
|
|
7
|
+
PersonRectangleIcon,
|
|
8
|
+
RemoveUserIcon,
|
|
9
|
+
VerticalMenuIcon,
|
|
10
|
+
VideoOffIcon,
|
|
11
|
+
VideoOnIcon,
|
|
12
|
+
} from '@100mslive/react-icons';
|
|
13
|
+
import { Dropdown } from '../../../Dropdown';
|
|
14
|
+
import { Flex } from '../../../Layout';
|
|
15
|
+
import { Text } from '../../../Text';
|
|
16
|
+
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
|
17
|
+
// @ts-ignore: No implicit Any
|
|
18
|
+
import { getMetadata } from '../../common/utils';
|
|
19
|
+
|
|
20
|
+
const dropdownItemCSS = { backgroundColor: '$surface_default', gap: '$4', p: '$8' };
|
|
21
|
+
const optionTextCSS = { fontWeight: '$semiBold', color: '$on_surface_high', textTransform: 'none' };
|
|
22
|
+
|
|
23
|
+
export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList: HMSPeer[] }) => {
|
|
24
|
+
const [openOptions, setOpenOptions] = useState(false);
|
|
25
|
+
const permissions = useHMSStore(selectPermissions);
|
|
26
|
+
const hmsActions = useHMSActions();
|
|
27
|
+
const { elements } = useRoomLayoutConferencingScreen();
|
|
28
|
+
const { on_stage_role, off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
|
|
29
|
+
|
|
30
|
+
const vanillaStore = useHMSVanillaStore();
|
|
31
|
+
const store = vanillaStore.getState();
|
|
32
|
+
|
|
33
|
+
let allPeersHaveVideoOn = true;
|
|
34
|
+
let allPeersHaveAudioOn = true;
|
|
35
|
+
|
|
36
|
+
peerList.forEach(peer => {
|
|
37
|
+
const isAudioOn = !!peer.audioTrack && store.tracks[peer.audioTrack]?.enabled;
|
|
38
|
+
const isVideoOn = !!peer.videoTrack && store.tracks[peer.videoTrack]?.enabled;
|
|
39
|
+
allPeersHaveAudioOn = allPeersHaveAudioOn && isAudioOn;
|
|
40
|
+
allPeersHaveVideoOn = allPeersHaveVideoOn && isVideoOn;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const canMuteRole = permissions?.mute && roleName === on_stage_role;
|
|
44
|
+
const canRemoveRoleFromStage = permissions?.changeRole && roleName === on_stage_role;
|
|
45
|
+
// on stage and off stage roles
|
|
46
|
+
const canRemoveRoleFromRoom =
|
|
47
|
+
permissions?.removeOthers && (on_stage_role === roleName || off_stage_roles?.includes(roleName));
|
|
48
|
+
|
|
49
|
+
if (!(canMuteRole || canRemoveRoleFromStage || canRemoveRoleFromRoom)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const removeAllFromStage = () => {
|
|
54
|
+
peerList.forEach(peer => {
|
|
55
|
+
const prevRole = getMetadata(peer.metadata).prevRole;
|
|
56
|
+
if (prevRole) {
|
|
57
|
+
hmsActions.changeRoleOfPeer(peer.id, prevRole, true);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const setTrackEnabled = async (type: 'audio' | 'video', enabled = false) => {
|
|
63
|
+
try {
|
|
64
|
+
await hmsActions.setRemoteTracksEnabled({ roles: [roleName], source: 'regular', type, enabled });
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.error(e);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const removePeersFromRoom = async () => {
|
|
71
|
+
try {
|
|
72
|
+
peerList.forEach(async peer => {
|
|
73
|
+
await hmsActions.removePeer(peer.id, '');
|
|
74
|
+
});
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error(e);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Dropdown.Root open={openOptions} onOpenChange={setOpenOptions}>
|
|
82
|
+
<Dropdown.Trigger
|
|
83
|
+
onClick={e => e.stopPropagation()}
|
|
84
|
+
className="role_actions"
|
|
85
|
+
asChild
|
|
86
|
+
css={{
|
|
87
|
+
p: '$1',
|
|
88
|
+
r: '$0',
|
|
89
|
+
c: '$on_surface_high',
|
|
90
|
+
visibility: openOptions ? 'visible' : 'hidden',
|
|
91
|
+
'&:hover': {
|
|
92
|
+
c: '$on_surface_medium',
|
|
93
|
+
},
|
|
94
|
+
'@md': {
|
|
95
|
+
visibility: 'visible',
|
|
96
|
+
},
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
<Flex>
|
|
100
|
+
<VerticalMenuIcon />
|
|
101
|
+
</Flex>
|
|
102
|
+
</Dropdown.Trigger>
|
|
103
|
+
<Dropdown.Content
|
|
104
|
+
onClick={e => e.stopPropagation()}
|
|
105
|
+
css={{ w: 'max-content', maxWidth: '$64', bg: '$surface_default', py: 0 }}
|
|
106
|
+
align="end"
|
|
107
|
+
>
|
|
108
|
+
{canRemoveRoleFromStage && (
|
|
109
|
+
<Dropdown.Item
|
|
110
|
+
css={{ ...dropdownItemCSS, borderBottom: '1px solid $border_bright' }}
|
|
111
|
+
onClick={removeAllFromStage}
|
|
112
|
+
>
|
|
113
|
+
<PersonRectangleIcon />
|
|
114
|
+
<Text variant="sm" css={optionTextCSS}>
|
|
115
|
+
Remove all from Stage
|
|
116
|
+
</Text>
|
|
117
|
+
</Dropdown.Item>
|
|
118
|
+
)}
|
|
119
|
+
|
|
120
|
+
{canMuteRole && (
|
|
121
|
+
<>
|
|
122
|
+
<Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', !allPeersHaveAudioOn)}>
|
|
123
|
+
{allPeersHaveAudioOn ? <MicOffIcon /> : <MicOnIcon />}
|
|
124
|
+
<Text variant="sm" css={optionTextCSS}>
|
|
125
|
+
{allPeersHaveAudioOn ? 'Mute' : 'Unmute'} Audio
|
|
126
|
+
</Text>
|
|
127
|
+
</Dropdown.Item>
|
|
128
|
+
|
|
129
|
+
<Dropdown.Item
|
|
130
|
+
css={{ ...dropdownItemCSS, borderTop: '1px solid $border_bright' }}
|
|
131
|
+
onClick={() => setTrackEnabled('video', !allPeersHaveVideoOn)}
|
|
132
|
+
>
|
|
133
|
+
{allPeersHaveVideoOn ? <VideoOffIcon /> : <VideoOnIcon />}
|
|
134
|
+
<Text variant="sm" css={optionTextCSS}>
|
|
135
|
+
{allPeersHaveVideoOn ? 'Mute' : 'Unmute'} Video
|
|
136
|
+
</Text>
|
|
137
|
+
</Dropdown.Item>
|
|
138
|
+
</>
|
|
139
|
+
)}
|
|
140
|
+
|
|
141
|
+
{canRemoveRoleFromRoom && (
|
|
142
|
+
<Dropdown.Item
|
|
143
|
+
css={{ ...dropdownItemCSS, borderTop: '1px solid $border_bright', color: '$alert_error_default' }}
|
|
144
|
+
onClick={removePeersFromRoom}
|
|
145
|
+
>
|
|
146
|
+
<RemoveUserIcon />
|
|
147
|
+
<Text variant="sm" css={{ ...optionTextCSS, color: 'inherit' }}>
|
|
148
|
+
Remove all from Room
|
|
149
|
+
</Text>
|
|
150
|
+
</Dropdown.Item>
|
|
151
|
+
)}
|
|
152
|
+
</Dropdown.Content>
|
|
153
|
+
</Dropdown.Root>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
@@ -3,10 +3,10 @@ import { Flex } from '../../Layout';
|
|
|
3
3
|
import { Loading } from '../../Loading';
|
|
4
4
|
import { Text } from '../../Text';
|
|
5
5
|
|
|
6
|
-
const FullPageProgress = ({ loaderColor = '$primary_default',
|
|
7
|
-
<Flex direction="column" justify="center" align="center" css={{ size: '100%', color: loaderColor }}>
|
|
6
|
+
const FullPageProgress = ({ loaderColor = '$primary_default', text = '', css = {} }) => (
|
|
7
|
+
<Flex direction="column" justify="center" align="center" css={{ size: '100%', color: loaderColor, ...css }}>
|
|
8
8
|
<Loading color="currentColor" size={100} />
|
|
9
|
-
{
|
|
9
|
+
{text ? <Text css={{ mt: '$10', color: '$on_surface_high' }}>{text}</Text> : null}
|
|
10
10
|
</Flex>
|
|
11
11
|
);
|
|
12
12
|
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CheckIcon, SettingsIcon } from '@100mslive/react-icons';
|
|
3
3
|
import { Box, Dropdown, Flex, Text, Tooltip } from '../../../';
|
|
4
4
|
|
|
5
|
-
export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto }) {
|
|
6
|
-
const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false);
|
|
7
|
-
|
|
5
|
+
export function HLSQualitySelector({ open, onOpen, layers, onQualityChange, selection, isAuto }) {
|
|
8
6
|
return (
|
|
9
|
-
<Dropdown.Root open={
|
|
7
|
+
<Dropdown.Root open={open} onOpenChange={value => onOpen(value)}>
|
|
10
8
|
<Dropdown.Trigger asChild data-testid="quality_selector">
|
|
11
9
|
<Flex
|
|
12
10
|
css={{
|
|
@@ -24,6 +22,7 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
|
24
22
|
h: '$9',
|
|
25
23
|
display: 'inline-flex',
|
|
26
24
|
alignItems: 'center',
|
|
25
|
+
c: '$on_surface_high',
|
|
27
26
|
}}
|
|
28
27
|
>
|
|
29
28
|
<SettingsIcon />
|
|
@@ -44,7 +43,7 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
|
44
43
|
mx: '$2',
|
|
45
44
|
w: '$2',
|
|
46
45
|
h: '$2',
|
|
47
|
-
background: '$
|
|
46
|
+
background: '$on_surface_medium',
|
|
48
47
|
r: '$1',
|
|
49
48
|
}}
|
|
50
49
|
/>
|
|
@@ -60,7 +59,15 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
|
60
59
|
<Dropdown.Content
|
|
61
60
|
sideOffset={5}
|
|
62
61
|
align="end"
|
|
63
|
-
css={{
|
|
62
|
+
css={{
|
|
63
|
+
height: 'auto',
|
|
64
|
+
maxHeight: '$52',
|
|
65
|
+
w: '$40',
|
|
66
|
+
bg: '$surface_bright',
|
|
67
|
+
py: '$4',
|
|
68
|
+
gap: '$4',
|
|
69
|
+
display: 'grid',
|
|
70
|
+
}}
|
|
64
71
|
>
|
|
65
72
|
{layers.map(layer => {
|
|
66
73
|
return (
|
|
@@ -68,16 +75,26 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
|
68
75
|
onClick={() => onQualityChange(layer)}
|
|
69
76
|
key={layer.width}
|
|
70
77
|
css={{
|
|
71
|
-
bg:
|
|
78
|
+
bg:
|
|
79
|
+
!isAuto && layer.width === selection?.width && layer.height === selection?.height
|
|
80
|
+
? '$surface_default'
|
|
81
|
+
: '$surface_bright',
|
|
72
82
|
'&:hover': {
|
|
73
|
-
bg: '$
|
|
83
|
+
bg: '$surface_brighter',
|
|
74
84
|
},
|
|
85
|
+
p: '$2 $4 $2 $8',
|
|
86
|
+
h: '$12',
|
|
87
|
+
gap: '$2',
|
|
75
88
|
}}
|
|
76
89
|
>
|
|
77
|
-
<Text
|
|
78
|
-
|
|
90
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold' }}>
|
|
91
|
+
{getQualityText(layer)}
|
|
92
|
+
</Text>
|
|
93
|
+
<Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
|
|
94
|
+
{getBitrateText(layer)}
|
|
95
|
+
</Text>
|
|
79
96
|
{!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
|
|
80
|
-
<
|
|
97
|
+
<CheckIcon width="16px" height="16px" />
|
|
81
98
|
)}
|
|
82
99
|
</Dropdown.Item>
|
|
83
100
|
);
|
|
@@ -86,14 +103,19 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
|
86
103
|
onClick={() => onQualityChange({ height: 'auto' })}
|
|
87
104
|
key="auto"
|
|
88
105
|
css={{
|
|
89
|
-
bg: '$surface_bright',
|
|
106
|
+
bg: !isAuto ? '$surface_bright' : '$surface_default',
|
|
90
107
|
'&:hover': {
|
|
91
|
-
bg: '$
|
|
108
|
+
bg: '$surface_brighter',
|
|
92
109
|
},
|
|
110
|
+
p: '$2 $4 $2 $8',
|
|
111
|
+
h: '$12',
|
|
112
|
+
gap: '$2',
|
|
93
113
|
}}
|
|
94
114
|
>
|
|
95
|
-
<Text css={{ flex: '1 1 0' }}>
|
|
96
|
-
|
|
115
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
|
|
116
|
+
Auto
|
|
117
|
+
</Text>
|
|
118
|
+
{isAuto && <CheckIcon width="16px" height="16px" />}
|
|
97
119
|
</Dropdown.Item>
|
|
98
120
|
</Dropdown.Content>
|
|
99
121
|
)}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import { Flex } from '../../../';
|
|
3
3
|
|
|
4
|
-
export const HMSVideo = forwardRef(({ children }, videoRef) => {
|
|
4
|
+
export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
|
|
5
5
|
return (
|
|
6
|
-
<Flex data-testid="hms-video" css={{ size: '100%' }} direction="column">
|
|
6
|
+
<Flex data-testid="hms-video" css={{ size: '100%', position: 'relative' }} direction="column" {...props}>
|
|
7
7
|
<video style={{ flex: '1 1 0', margin: '0 auto', minHeight: '0' }} ref={videoRef} playsInline />
|
|
8
8
|
{children}
|
|
9
9
|
</Flex>
|
|
@@ -44,7 +44,7 @@ export const VideoProgress = ({ onValueChange, hlsPlayer }) => {
|
|
|
44
44
|
return hlsPlayer.getVideoElement() ? (
|
|
45
45
|
<Flex
|
|
46
46
|
ref={progressRootRef}
|
|
47
|
-
css={{
|
|
47
|
+
css={{ cursor: 'pointer', h: '$4', alignSelf: 'stretch' }}
|
|
48
48
|
onClick={onProgressChangeHandler}
|
|
49
49
|
>
|
|
50
50
|
<Box
|
|
@@ -53,23 +53,22 @@ export const VideoProgress = ({ onValueChange, hlsPlayer }) => {
|
|
|
53
53
|
display: 'inline',
|
|
54
54
|
width: `${videoProgress}%`,
|
|
55
55
|
background: '$primary_default',
|
|
56
|
-
height: '0.3rem',
|
|
57
56
|
}}
|
|
58
57
|
/>
|
|
59
58
|
<Box
|
|
60
59
|
id="video-buffer"
|
|
61
60
|
css={{
|
|
62
61
|
width: `${bufferProgress - videoProgress}%`,
|
|
63
|
-
background: '$
|
|
64
|
-
|
|
62
|
+
background: '$on_surface_high',
|
|
63
|
+
opacity: '25%',
|
|
65
64
|
}}
|
|
66
65
|
/>
|
|
67
66
|
<Box
|
|
68
67
|
id="video-rest"
|
|
69
68
|
css={{
|
|
70
69
|
width: `${100 - bufferProgress}%`,
|
|
71
|
-
background: '$
|
|
72
|
-
|
|
70
|
+
background: '$on_surface_high',
|
|
71
|
+
opacity: '10%',
|
|
73
72
|
}}
|
|
74
73
|
/>
|
|
75
74
|
</Flex>
|
|
@@ -11,26 +11,31 @@ import {
|
|
|
11
11
|
useRecordingStreaming,
|
|
12
12
|
} from '@100mslive/react-sdk';
|
|
13
13
|
import { AlertTriangleIcon, CrossIcon, RecordIcon } from '@100mslive/react-icons';
|
|
14
|
-
import { Box, Button, config as cssConfig, Flex, HorizontalDivider, Loading, Popover, Text, Tooltip } from '
|
|
14
|
+
import { Box, Button, config as cssConfig, Flex, HorizontalDivider, Loading, Popover, Text, Tooltip } from '../../..';
|
|
15
15
|
import { Sheet } from '../../../Sheet';
|
|
16
|
+
// @ts-ignore
|
|
16
17
|
import { ToastManager } from '../Toast/ToastManager';
|
|
18
|
+
// @ts-ignore
|
|
17
19
|
import { AdditionalRoomState, getRecordingText } from './AdditionalRoomState';
|
|
20
|
+
// @ts-ignore
|
|
18
21
|
import { useSetAppDataByKey } from '../AppData/useUISettings';
|
|
22
|
+
// @ts-ignore
|
|
19
23
|
import { formatTime } from '../../common/utils';
|
|
24
|
+
// @ts-ignore
|
|
20
25
|
import { APP_DATA } from '../../common/constants';
|
|
21
26
|
|
|
22
27
|
export const LiveStatus = () => {
|
|
23
28
|
const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
|
|
24
29
|
const hlsState = useHMSStore(selectHLSState);
|
|
25
30
|
const isMobile = useMedia(cssConfig.media.md);
|
|
26
|
-
const intervalRef = useRef(null);
|
|
31
|
+
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
|
27
32
|
|
|
28
33
|
const [liveTime, setLiveTime] = useState(0);
|
|
29
34
|
|
|
30
35
|
const startTimer = useCallback(() => {
|
|
31
36
|
intervalRef.current = setInterval(() => {
|
|
32
|
-
if (hlsState?.running) {
|
|
33
|
-
setLiveTime(Date.now() - hlsState
|
|
37
|
+
if (hlsState?.running && hlsState?.variants[0]?.startedAt) {
|
|
38
|
+
setLiveTime(Date.now() - hlsState.variants[0].startedAt.getTime());
|
|
34
39
|
}
|
|
35
40
|
}, 1000);
|
|
36
41
|
}, [hlsState?.running, hlsState?.variants]);
|
|
@@ -90,6 +95,7 @@ export const RecordingStatus = () => {
|
|
|
90
95
|
|
|
91
96
|
return (
|
|
92
97
|
<Tooltip
|
|
98
|
+
boxCss={{ zIndex: 1 }}
|
|
93
99
|
title={getRecordingText({
|
|
94
100
|
isBrowserRecordingOn,
|
|
95
101
|
isServerRecordingOn,
|
|
@@ -130,7 +136,7 @@ const StartRecording = () => {
|
|
|
130
136
|
</Popover.Trigger>
|
|
131
137
|
<Popover.Portal>
|
|
132
138
|
<Popover.Content align="end" sideOffset={8} css={{ w: '$64' }}>
|
|
133
|
-
<Text variant="
|
|
139
|
+
<Text variant="body1" css={{ color: '$on_surface_medium' }}>
|
|
134
140
|
Are you sure you want to end the recording?
|
|
135
141
|
</Text>
|
|
136
142
|
<Button
|
|
@@ -142,8 +148,9 @@ const StartRecording = () => {
|
|
|
142
148
|
try {
|
|
143
149
|
await hmsActions.stopRTMPAndRecording();
|
|
144
150
|
} catch (error) {
|
|
151
|
+
const err = error as Error;
|
|
145
152
|
ToastManager.addToast({
|
|
146
|
-
title:
|
|
153
|
+
title: err.message,
|
|
147
154
|
variant: 'error',
|
|
148
155
|
});
|
|
149
156
|
}
|
|
@@ -170,14 +177,15 @@ const StartRecording = () => {
|
|
|
170
177
|
record: true,
|
|
171
178
|
});
|
|
172
179
|
} catch (error) {
|
|
173
|
-
|
|
180
|
+
const err = error as Error;
|
|
181
|
+
if (err.message.includes('stream already running')) {
|
|
174
182
|
ToastManager.addToast({
|
|
175
183
|
title: 'Recording already running',
|
|
176
184
|
variant: 'error',
|
|
177
185
|
});
|
|
178
186
|
} else {
|
|
179
187
|
ToastManager.addToast({
|
|
180
|
-
title:
|
|
188
|
+
title: err.message,
|
|
181
189
|
variant: 'error',
|
|
182
190
|
});
|
|
183
191
|
}
|
|
@@ -215,7 +223,13 @@ export const StreamActions = () => {
|
|
|
215
223
|
);
|
|
216
224
|
};
|
|
217
225
|
|
|
218
|
-
export const StopRecordingInSheet = ({
|
|
226
|
+
export const StopRecordingInSheet = ({
|
|
227
|
+
onStopRecording,
|
|
228
|
+
onClose,
|
|
229
|
+
}: {
|
|
230
|
+
onStopRecording: () => void;
|
|
231
|
+
onClose: () => void;
|
|
232
|
+
}) => {
|
|
219
233
|
return (
|
|
220
234
|
<Sheet.Root open={true}>
|
|
221
235
|
<Sheet.Content>
|
|
@@ -25,11 +25,13 @@ export const CamaraFlipActions = () => {
|
|
|
25
25
|
|
|
26
26
|
const videoTrackId = useHMSStore(selectLocalVideoTrackID);
|
|
27
27
|
const localVideoTrack = useHMSStore(selectVideoTrackByID(videoTrackId));
|
|
28
|
-
|
|
28
|
+
if (!videoInput || !videoInput?.length || !localVideoTrack?.facingMode) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
29
31
|
return (
|
|
30
32
|
<Box>
|
|
31
33
|
<IconButton
|
|
32
|
-
disabled={!
|
|
34
|
+
disabled={!isVideoOn}
|
|
33
35
|
onClick={async () => {
|
|
34
36
|
try {
|
|
35
37
|
await actions.switchCamera();
|
|
@@ -117,6 +119,7 @@ const AudioOutputSelectionSheet = ({ outputDevices, outputSelected, onChange, ch
|
|
|
117
119
|
{outputDevices.map(audioDevice => {
|
|
118
120
|
return (
|
|
119
121
|
<SelectWithLabel
|
|
122
|
+
key={audioDevice.deviceId}
|
|
120
123
|
label={audioDevice.label}
|
|
121
124
|
id={audioDevice.deviceId}
|
|
122
125
|
checked={audioDevice.deviceId === outputSelected}
|
|
@@ -14,6 +14,10 @@ const IconSection = styled(IconButton, {
|
|
|
14
14
|
borderTopRightRadius: 0,
|
|
15
15
|
borderColor: '$border_default',
|
|
16
16
|
borderBottomRightRadius: 0,
|
|
17
|
+
position: 'relative',
|
|
18
|
+
'&:not([disabled]):focus-visible': {
|
|
19
|
+
zIndex: 1,
|
|
20
|
+
},
|
|
17
21
|
'@md': {
|
|
18
22
|
mx: 0,
|
|
19
23
|
borderTopRightRadius: '$1',
|
|
@@ -30,8 +34,9 @@ const OptionsSection = styled(IconButton, {
|
|
|
30
34
|
borderColor: '$border_default',
|
|
31
35
|
borderBottomLeftRadius: 0,
|
|
32
36
|
borderLeftWidth: 0,
|
|
37
|
+
position: 'relative',
|
|
33
38
|
'&:not([disabled]):focus-visible': {
|
|
34
|
-
|
|
39
|
+
zIndex: 1,
|
|
35
40
|
},
|
|
36
41
|
'@md': {
|
|
37
42
|
display: 'none',
|
|
@@ -14,6 +14,7 @@ import { AudioVideoToggle } from './AudioVideoToggle';
|
|
|
14
14
|
import VideoTile from './VideoTile';
|
|
15
15
|
// @ts-ignore: No implicit Any
|
|
16
16
|
import { useSetAppDataByKey } from './AppData/useUISettings';
|
|
17
|
+
import { useVideoTileContext } from './hooks/useVideoTileLayout';
|
|
17
18
|
// @ts-ignore: No implicit Any
|
|
18
19
|
import { APP_DATA } from '../common/constants';
|
|
19
20
|
|
|
@@ -22,7 +23,11 @@ const MinimisedTile = ({ setMinimised }: { setMinimised: (value: boolean) => voi
|
|
|
22
23
|
<Flex align="center" css={{ gap: '$6', r: '$1', bg: '$surface_default', p: '$4', color: '$on_surface_high' }}>
|
|
23
24
|
<AudioVideoToggle hideOptions={true} />
|
|
24
25
|
<Text>You</Text>
|
|
25
|
-
<IconButton
|
|
26
|
+
<IconButton
|
|
27
|
+
className="__cancel-drag-event"
|
|
28
|
+
onClick={() => setMinimised(false)}
|
|
29
|
+
css={{ bg: 'transparent', border: 'transparent' }}
|
|
30
|
+
>
|
|
26
31
|
<ExpandIcon />
|
|
27
32
|
</IconButton>
|
|
28
33
|
</Flex>
|
|
@@ -41,12 +46,11 @@ export const InsetTile = () => {
|
|
|
41
46
|
const [minimised, setMinimised] = useSetAppDataByKey(APP_DATA.minimiseInset);
|
|
42
47
|
const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack));
|
|
43
48
|
const isAllowedToPublish = useHMSStore(selectIsAllowedToPublish);
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
: desktopAspectRatio;
|
|
49
|
+
const videoTileProps = useVideoTileContext();
|
|
50
|
+
let aspectRatio = isMobile ? defaultMobileAspectRatio : desktopAspectRatio;
|
|
51
|
+
if (videoTrack?.width && videoTrack?.height && !isMobile) {
|
|
52
|
+
aspectRatio = videoTrack.width / videoTrack.height;
|
|
53
|
+
}
|
|
50
54
|
let height = insetHeightPx;
|
|
51
55
|
let width = height * aspectRatio;
|
|
52
56
|
// Convert to 16/9 in landscape mode with a max width of 240
|
|
@@ -82,7 +86,7 @@ export const InsetTile = () => {
|
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
return (
|
|
85
|
-
<Draggable bounds="parent" nodeRef={nodeRef}>
|
|
89
|
+
<Draggable bounds="parent" nodeRef={nodeRef} cancel=".__cancel-drag-event">
|
|
86
90
|
<Box
|
|
87
91
|
ref={nodeRef}
|
|
88
92
|
css={{
|
|
@@ -114,6 +118,8 @@ export const InsetTile = () => {
|
|
|
114
118
|
height={height}
|
|
115
119
|
containerCSS={{ background: '$surface_default' }}
|
|
116
120
|
canMinimise
|
|
121
|
+
isDragabble
|
|
122
|
+
{...videoTileProps}
|
|
117
123
|
/>
|
|
118
124
|
)}
|
|
119
125
|
</Box>
|