@stream-io/video-react-native-sdk 0.0.1-alpha.141
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/CHANGELOG.md +739 -0
- package/LICENSE +219 -0
- package/README.md +19 -0
- package/dist/__tests__/components/ActiveCall.test.d.ts +1 -0
- package/dist/__tests__/components/ActiveCall.test.js +89 -0
- package/dist/__tests__/components/ActiveCall.test.js.map +1 -0
- package/dist/__tests__/components/Avatar.test.d.ts +1 -0
- package/dist/__tests__/components/Avatar.test.js +34 -0
- package/dist/__tests__/components/Avatar.test.js.map +1 -0
- package/dist/__tests__/components/ParticipantView.test.d.ts +1 -0
- package/dist/__tests__/components/ParticipantView.test.js +66 -0
- package/dist/__tests__/components/ParticipantView.test.js.map +1 -0
- package/dist/__tests__/mocks/call.d.ts +2 -0
- package/dist/__tests__/mocks/call.js +21 -0
- package/dist/__tests__/mocks/call.js.map +1 -0
- package/dist/__tests__/mocks/client.d.ts +2 -0
- package/dist/__tests__/mocks/client.js +31 -0
- package/dist/__tests__/mocks/client.js.map +1 -0
- package/dist/__tests__/mocks/participant.d.ts +3 -0
- package/dist/__tests__/mocks/participant.js +25 -0
- package/dist/__tests__/mocks/participant.js.map +1 -0
- package/dist/__tests__/utils/RNTLTools.d.ts +15 -0
- package/dist/__tests__/utils/RNTLTools.js +54 -0
- package/dist/__tests__/utils/RNTLTools.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/jest-setup.d.ts +1 -0
- package/dist/jest-setup.js +34 -0
- package/dist/jest-setup.js.map +1 -0
- package/dist/src/components/ActiveCall.d.ts +18 -0
- package/dist/src/components/ActiveCall.js +117 -0
- package/dist/src/components/ActiveCall.js.map +1 -0
- package/dist/src/components/Avatar.d.ts +25 -0
- package/dist/src/components/Avatar.js +55 -0
- package/dist/src/components/Avatar.js.map +1 -0
- package/dist/src/components/CallControlsButton.d.ts +22 -0
- package/dist/src/components/CallControlsButton.js +43 -0
- package/dist/src/components/CallControlsButton.js.map +1 -0
- package/dist/src/components/CallControlsView.d.ts +9 -0
- package/dist/src/components/CallControlsView.js +95 -0
- package/dist/src/components/CallControlsView.js.map +1 -0
- package/dist/src/components/CallParticipantsBadge.d.ts +1 -0
- package/dist/src/components/CallParticipantsBadge.js +48 -0
- package/dist/src/components/CallParticipantsBadge.js.map +1 -0
- package/dist/src/components/CallParticipantsInfoView.d.ts +21 -0
- package/dist/src/components/CallParticipantsInfoView.js +213 -0
- package/dist/src/components/CallParticipantsInfoView.js.map +1 -0
- package/dist/src/components/CallParticipantsList.d.ts +25 -0
- package/dist/src/components/CallParticipantsList.js +124 -0
- package/dist/src/components/CallParticipantsList.js.map +1 -0
- package/dist/src/components/CallParticipantsOptions.d.ts +8 -0
- package/dist/src/components/CallParticipantsOptions.js +189 -0
- package/dist/src/components/CallParticipantsOptions.js.map +1 -0
- package/dist/src/components/CallParticipantsSpotlightView.d.ts +1 -0
- package/dist/src/components/CallParticipantsSpotlightView.js +40 -0
- package/dist/src/components/CallParticipantsSpotlightView.js.map +1 -0
- package/dist/src/components/CallParticipantsView.d.ts +1 -0
- package/dist/src/components/CallParticipantsView.js +31 -0
- package/dist/src/components/CallParticipantsView.js.map +1 -0
- package/dist/src/components/IncomingCallView.d.ts +1 -0
- package/dist/src/components/IncomingCallView.js +98 -0
- package/dist/src/components/IncomingCallView.js.map +1 -0
- package/dist/src/components/LobbyView.d.ts +1 -0
- package/dist/src/components/LobbyView.js +215 -0
- package/dist/src/components/LobbyView.js.map +1 -0
- package/dist/src/components/LocalVideoView.d.ts +34 -0
- package/dist/src/components/LocalVideoView.js +100 -0
- package/dist/src/components/LocalVideoView.js.map +1 -0
- package/dist/src/components/NetworkQualityIndicator.d.ts +8 -0
- package/dist/src/components/NetworkQualityIndicator.js +36 -0
- package/dist/src/components/NetworkQualityIndicator.js.map +1 -0
- package/dist/src/components/OutgoingCallView.d.ts +1 -0
- package/dist/src/components/OutgoingCallView.js +103 -0
- package/dist/src/components/OutgoingCallView.js.map +1 -0
- package/dist/src/components/ParticipantReaction.d.ts +7 -0
- package/dist/src/components/ParticipantReaction.js +45 -0
- package/dist/src/components/ParticipantReaction.js.map +1 -0
- package/dist/src/components/ParticipantView.d.ts +42 -0
- package/dist/src/components/ParticipantView.js +256 -0
- package/dist/src/components/ParticipantView.js.map +1 -0
- package/dist/src/components/ReactionsModal.d.ts +7 -0
- package/dist/src/components/ReactionsModal.js +65 -0
- package/dist/src/components/ReactionsModal.js.map +1 -0
- package/dist/src/components/ToggleAudioButton.d.ts +1 -0
- package/dist/src/components/ToggleAudioButton.js +78 -0
- package/dist/src/components/ToggleAudioButton.js.map +1 -0
- package/dist/src/components/ToggleVideoButton.d.ts +1 -0
- package/dist/src/components/ToggleVideoButton.js +78 -0
- package/dist/src/components/ToggleVideoButton.js.map +1 -0
- package/dist/src/components/UserInfoView.d.ts +13 -0
- package/dist/src/components/UserInfoView.js +82 -0
- package/dist/src/components/UserInfoView.js.map +1 -0
- package/dist/src/components/VideoRenderer.d.ts +65 -0
- package/dist/src/components/VideoRenderer.js +18 -0
- package/dist/src/components/VideoRenderer.js.map +1 -0
- package/dist/src/components/index.d.ts +12 -0
- package/dist/src/components/index.js +29 -0
- package/dist/src/components/index.js.map +1 -0
- package/dist/src/constants/A11yLabels.d.ts +20 -0
- package/dist/src/constants/A11yLabels.js +29 -0
- package/dist/src/constants/A11yLabels.js.map +1 -0
- package/dist/src/constants/index.d.ts +11 -0
- package/dist/src/constants/index.js +30 -0
- package/dist/src/constants/index.js.map +1 -0
- package/dist/src/contexts/StreamVideoContext/createStoreContext.d.ts +14 -0
- package/dist/src/contexts/StreamVideoContext/createStoreContext.js +100 -0
- package/dist/src/contexts/StreamVideoContext/createStoreContext.js.map +1 -0
- package/dist/src/contexts/StreamVideoContext/index.d.ts +30 -0
- package/dist/src/contexts/StreamVideoContext/index.js +18 -0
- package/dist/src/contexts/StreamVideoContext/index.js.map +1 -0
- package/dist/src/contexts/index.d.ts +1 -0
- package/dist/src/contexts/index.js +18 -0
- package/dist/src/contexts/index.js.map +1 -0
- package/dist/src/hooks/index.d.ts +10 -0
- package/dist/src/hooks/index.js +27 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/useCallControls.d.ts +14 -0
- package/dist/src/hooks/useCallControls.js +148 -0
- package/dist/src/hooks/useCallControls.js.map +1 -0
- package/dist/src/hooks/useCallCycleEffect.d.ts +8 -0
- package/dist/src/hooks/useCallCycleEffect.js +62 -0
- package/dist/src/hooks/useCallCycleEffect.js.map +1 -0
- package/dist/src/hooks/useCallKeep.d.ts +11 -0
- package/dist/src/hooks/useCallKeep.js +41 -0
- package/dist/src/hooks/useCallKeep.js.map +1 -0
- package/dist/src/hooks/useCreateStreamVideoClient.d.ts +33 -0
- package/dist/src/hooks/useCreateStreamVideoClient.js +40 -0
- package/dist/src/hooks/useCreateStreamVideoClient.js.map +1 -0
- package/dist/src/hooks/useIncallManager.d.ts +13 -0
- package/dist/src/hooks/useIncallManager.js +24 -0
- package/dist/src/hooks/useIncallManager.js.map +1 -0
- package/dist/src/hooks/useLocalVideoStream.d.ts +7 -0
- package/dist/src/hooks/useLocalVideoStream.js +34 -0
- package/dist/src/hooks/useLocalVideoStream.js.map +1 -0
- package/dist/src/hooks/useMutingState.d.ts +12 -0
- package/dist/src/hooks/useMutingState.js +25 -0
- package/dist/src/hooks/useMutingState.js.map +1 -0
- package/dist/src/hooks/usePermissionNotification.d.ts +18 -0
- package/dist/src/hooks/usePermissionNotification.js +33 -0
- package/dist/src/hooks/usePermissionNotification.js.map +1 -0
- package/dist/src/hooks/usePermissionRequest.d.ts +1 -0
- package/dist/src/hooks/usePermissionRequest.js +62 -0
- package/dist/src/hooks/usePermissionRequest.js.map +1 -0
- package/dist/src/hooks/usePublishMediaStreams.d.ts +6 -0
- package/dist/src/hooks/usePublishMediaStreams.js +49 -0
- package/dist/src/hooks/usePublishMediaStreams.js.map +1 -0
- package/dist/src/icons/ArrowRight.d.ts +5 -0
- package/dist/src/icons/ArrowRight.js +9 -0
- package/dist/src/icons/ArrowRight.js.map +1 -0
- package/dist/src/icons/CameraSwitch.d.ts +5 -0
- package/dist/src/icons/CameraSwitch.js +9 -0
- package/dist/src/icons/CameraSwitch.js.map +1 -0
- package/dist/src/icons/Chat.d.ts +5 -0
- package/dist/src/icons/Chat.js +9 -0
- package/dist/src/icons/Chat.js.map +1 -0
- package/dist/src/icons/Cross.d.ts +5 -0
- package/dist/src/icons/Cross.js +9 -0
- package/dist/src/icons/Cross.js.map +1 -0
- package/dist/src/icons/Mic.d.ts +5 -0
- package/dist/src/icons/Mic.js +10 -0
- package/dist/src/icons/Mic.js.map +1 -0
- package/dist/src/icons/MicOff.d.ts +5 -0
- package/dist/src/icons/MicOff.js +9 -0
- package/dist/src/icons/MicOff.js.map +1 -0
- package/dist/src/icons/Participants.d.ts +5 -0
- package/dist/src/icons/Participants.js +9 -0
- package/dist/src/icons/Participants.js.map +1 -0
- package/dist/src/icons/Phone.d.ts +5 -0
- package/dist/src/icons/Phone.js +9 -0
- package/dist/src/icons/Phone.js.map +1 -0
- package/dist/src/icons/PhoneDown.d.ts +5 -0
- package/dist/src/icons/PhoneDown.js +10 -0
- package/dist/src/icons/PhoneDown.js.map +1 -0
- package/dist/src/icons/Pin.d.ts +5 -0
- package/dist/src/icons/Pin.js +9 -0
- package/dist/src/icons/Pin.js.map +1 -0
- package/dist/src/icons/Reaction.d.ts +5 -0
- package/dist/src/icons/Reaction.js +9 -0
- package/dist/src/icons/Reaction.js.map +1 -0
- package/dist/src/icons/ScreenShare.d.ts +5 -0
- package/dist/src/icons/ScreenShare.js +40 -0
- package/dist/src/icons/ScreenShare.js.map +1 -0
- package/dist/src/icons/Settings.d.ts +5 -0
- package/dist/src/icons/Settings.js +34 -0
- package/dist/src/icons/Settings.js.map +1 -0
- package/dist/src/icons/Spotlight.d.ts +5 -0
- package/dist/src/icons/Spotlight.js +9 -0
- package/dist/src/icons/Spotlight.js.map +1 -0
- package/dist/src/icons/ThreeDots.d.ts +5 -0
- package/dist/src/icons/ThreeDots.js +11 -0
- package/dist/src/icons/ThreeDots.js.map +1 -0
- package/dist/src/icons/Video.d.ts +5 -0
- package/dist/src/icons/Video.js +9 -0
- package/dist/src/icons/Video.js.map +1 -0
- package/dist/src/icons/VideoDisabled.d.ts +5 -0
- package/dist/src/icons/VideoDisabled.js +10 -0
- package/dist/src/icons/VideoDisabled.js.map +1 -0
- package/dist/src/icons/VideoOff.d.ts +5 -0
- package/dist/src/icons/VideoOff.js +10 -0
- package/dist/src/icons/VideoOff.js.map +1 -0
- package/dist/src/icons/VideoSlash.d.ts +5 -0
- package/dist/src/icons/VideoSlash.js +10 -0
- package/dist/src/icons/VideoSlash.js.map +1 -0
- package/dist/src/icons/index.d.ts +19 -0
- package/dist/src/icons/index.js +36 -0
- package/dist/src/icons/index.js.map +1 -0
- package/dist/src/providers/MediaDevices.d.ts +9 -0
- package/dist/src/providers/MediaDevices.js +43 -0
- package/dist/src/providers/MediaDevices.js.map +1 -0
- package/dist/src/providers/StreamCall.d.ts +81 -0
- package/dist/src/providers/StreamCall.js +74 -0
- package/dist/src/providers/StreamCall.js.map +1 -0
- package/dist/src/providers/StreamVideo.d.ts +10 -0
- package/dist/src/providers/StreamVideo.js +66 -0
- package/dist/src/providers/StreamVideo.js.map +1 -0
- package/dist/src/providers/index.d.ts +2 -0
- package/dist/src/providers/index.js +19 -0
- package/dist/src/providers/index.js.map +1 -0
- package/dist/src/theme/avatar.d.ts +2 -0
- package/dist/src/theme/avatar.js +11 -0
- package/dist/src/theme/avatar.js.map +1 -0
- package/dist/src/theme/button.d.ts +2 -0
- package/dist/src/theme/button.js +11 -0
- package/dist/src/theme/button.js.map +1 -0
- package/dist/src/theme/colors.d.ts +3 -0
- package/dist/src/theme/colors.js +49 -0
- package/dist/src/theme/colors.js.map +1 -0
- package/dist/src/theme/constants.d.ts +47 -0
- package/dist/src/theme/constants.js +54 -0
- package/dist/src/theme/constants.js.map +1 -0
- package/dist/src/theme/fonts.d.ts +2 -0
- package/dist/src/theme/fonts.js +67 -0
- package/dist/src/theme/fonts.js.map +1 -0
- package/dist/src/theme/icon.d.ts +2 -0
- package/dist/src/theme/icon.js +11 -0
- package/dist/src/theme/icon.js.map +1 -0
- package/dist/src/theme/index.d.ts +2 -0
- package/dist/src/theme/index.js +26 -0
- package/dist/src/theme/index.js.map +1 -0
- package/dist/src/theme/margin.d.ts +2 -0
- package/dist/src/theme/margin.js +11 -0
- package/dist/src/theme/margin.js.map +1 -0
- package/dist/src/theme/padding.d.ts +2 -0
- package/dist/src/theme/padding.js +11 -0
- package/dist/src/theme/padding.js.map +1 -0
- package/dist/src/theme/rounded.d.ts +2 -0
- package/dist/src/theme/rounded.js +11 -0
- package/dist/src/theme/rounded.js.map +1 -0
- package/dist/src/theme/spacing.d.ts +2 -0
- package/dist/src/theme/spacing.js +11 -0
- package/dist/src/theme/spacing.js.map +1 -0
- package/dist/src/theme/types.d.ts +45 -0
- package/dist/src/theme/types.js +3 -0
- package/dist/src/theme/types.js.map +1 -0
- package/dist/src/utils/StreamVideoRN.d.ts +25 -0
- package/dist/src/utils/StreamVideoRN.js +23 -0
- package/dist/src/utils/StreamVideoRN.js.map +1 -0
- package/dist/src/utils/hooks/index.d.ts +3 -0
- package/dist/src/utils/hooks/index.js +20 -0
- package/dist/src/utils/hooks/index.js.map +1 -0
- package/dist/src/utils/hooks/useAppStateListener.d.ts +1 -0
- package/dist/src/utils/hooks/useAppStateListener.js +41 -0
- package/dist/src/utils/hooks/useAppStateListener.js.map +1 -0
- package/dist/src/utils/hooks/useDebouncedValue.d.ts +7 -0
- package/dist/src/utils/hooks/useDebouncedValue.js +22 -0
- package/dist/src/utils/hooks/useDebouncedValue.js.map +1 -0
- package/dist/src/utils/hooks/usePrevious.d.ts +1 -0
- package/dist/src/utils/hooks/usePrevious.js +13 -0
- package/dist/src/utils/hooks/usePrevious.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.js +53 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/verifyAndroidBluetoothPermissions.d.ts +1 -0
- package/dist/src/utils/verifyAndroidBluetoothPermissions.js +30 -0
- package/dist/src/utils/verifyAndroidBluetoothPermissions.js.map +1 -0
- package/index.ts +22 -0
- package/package.json +70 -0
- package/src/components/ActiveCall.tsx +122 -0
- package/src/components/Avatar.tsx +88 -0
- package/src/components/CallControlsButton.tsx +72 -0
- package/src/components/CallControlsView.tsx +128 -0
- package/src/components/CallParticipantsBadge.tsx +57 -0
- package/src/components/CallParticipantsInfoView.tsx +287 -0
- package/src/components/CallParticipantsList.tsx +172 -0
- package/src/components/CallParticipantsOptions.tsx +248 -0
- package/src/components/CallParticipantsSpotlightView.tsx +53 -0
- package/src/components/CallParticipantsView.tsx +30 -0
- package/src/components/IncomingCallView.tsx +133 -0
- package/src/components/LobbyView.tsx +236 -0
- package/src/components/LocalVideoView.tsx +141 -0
- package/src/components/NetworkQualityIndicator.tsx +72 -0
- package/src/components/OutgoingCallView.tsx +133 -0
- package/src/components/ParticipantReaction.tsx +59 -0
- package/src/components/ParticipantView.tsx +315 -0
- package/src/components/ReactionsModal.tsx +90 -0
- package/src/components/ToggleAudioButton.tsx +103 -0
- package/src/components/ToggleVideoButton.tsx +103 -0
- package/src/components/UserInfoView.tsx +118 -0
- package/src/components/VideoRenderer.tsx +85 -0
- package/src/components/index.ts +12 -0
- package/src/constants/A11yLabels.ts +24 -0
- package/src/constants/index.ts +28 -0
- package/src/contexts/StreamVideoContext/createStoreContext.tsx +117 -0
- package/src/contexts/StreamVideoContext/index.tsx +37 -0
- package/src/contexts/index.ts +1 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/useCallControls.tsx +186 -0
- package/src/hooks/useCallCycleEffect.tsx +68 -0
- package/src/hooks/useCallKeep.tsx +51 -0
- package/src/hooks/useCreateStreamVideoClient.tsx +77 -0
- package/src/hooks/useIncallManager.tsx +23 -0
- package/src/hooks/useLocalVideoStream.ts +36 -0
- package/src/hooks/useMutingState.ts +24 -0
- package/src/hooks/usePermissionNotification.tsx +53 -0
- package/src/hooks/usePermissionRequest.tsx +67 -0
- package/src/hooks/usePublishMediaStreams.ts +59 -0
- package/src/icons/ArrowRight.tsx +16 -0
- package/src/icons/CameraSwitch.tsx +14 -0
- package/src/icons/Chat.tsx +14 -0
- package/src/icons/Cross.tsx +14 -0
- package/src/icons/Mic.tsx +18 -0
- package/src/icons/MicOff.tsx +14 -0
- package/src/icons/Participants.tsx +16 -0
- package/src/icons/Phone.tsx +14 -0
- package/src/icons/PhoneDown.tsx +15 -0
- package/src/icons/Pin.tsx +16 -0
- package/src/icons/Reaction.tsx +14 -0
- package/src/icons/ScreenShare.tsx +32 -0
- package/src/icons/Settings.tsx +13 -0
- package/src/icons/Spotlight.tsx +16 -0
- package/src/icons/ThreeDots.tsx +13 -0
- package/src/icons/Video.tsx +14 -0
- package/src/icons/VideoDisabled.tsx +22 -0
- package/src/icons/VideoOff.tsx +20 -0
- package/src/icons/VideoSlash.tsx +15 -0
- package/src/icons/index.tsx +19 -0
- package/src/providers/MediaDevices.tsx +45 -0
- package/src/providers/StreamCall.tsx +136 -0
- package/src/providers/StreamVideo.tsx +50 -0
- package/src/providers/index.ts +2 -0
- package/src/theme/avatar.ts +9 -0
- package/src/theme/button.ts +9 -0
- package/src/theme/colors.ts +49 -0
- package/src/theme/constants.ts +51 -0
- package/src/theme/fonts.ts +65 -0
- package/src/theme/icon.ts +9 -0
- package/src/theme/index.ts +25 -0
- package/src/theme/margin.ts +9 -0
- package/src/theme/padding.ts +9 -0
- package/src/theme/rounded.ts +9 -0
- package/src/theme/spacing.ts +9 -0
- package/src/theme/types.ts +64 -0
- package/src/utils/StreamVideoRN.ts +35 -0
- package/src/utils/hooks/index.ts +3 -0
- package/src/utils/hooks/useAppStateListener.ts +48 -0
- package/src/utils/hooks/useDebouncedValue.ts +21 -0
- package/src/utils/hooks/usePrevious.ts +11 -0
- package/src/utils/index.ts +45 -0
- package/src/utils/verifyAndroidBluetoothPermissions.ts +31 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { AxiosError, OwnCapability } from '@stream-io/video-client';
|
|
2
|
+
import {
|
|
3
|
+
Restricted,
|
|
4
|
+
useCall,
|
|
5
|
+
useHasPermissions,
|
|
6
|
+
} from '@stream-io/video-react-bindings';
|
|
7
|
+
import { CallControlsButton } from './CallControlsButton';
|
|
8
|
+
import { muteStatusColor } from '../utils';
|
|
9
|
+
import { Alert, StyleSheet } from 'react-native';
|
|
10
|
+
import { theme } from '../theme';
|
|
11
|
+
import { Video, VideoSlash } from '../icons';
|
|
12
|
+
import { useCallControls, usePermissionNotification } from '../hooks';
|
|
13
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
14
|
+
|
|
15
|
+
export const ToggleVideoButton = () => {
|
|
16
|
+
const [isAwaitingApproval, setIsAwaitingApproval] = useState(false);
|
|
17
|
+
const { toggleVideoMuted, isVideoPublished } = useCallControls();
|
|
18
|
+
|
|
19
|
+
const isVideoMuted = !isVideoPublished;
|
|
20
|
+
|
|
21
|
+
const userHasSendVideoCapability = useHasPermissions(
|
|
22
|
+
OwnCapability.SEND_VIDEO,
|
|
23
|
+
);
|
|
24
|
+
const call = useCall();
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (userHasSendVideoCapability) {
|
|
28
|
+
setIsAwaitingApproval(false);
|
|
29
|
+
}
|
|
30
|
+
}, [userHasSendVideoCapability]);
|
|
31
|
+
|
|
32
|
+
const handleRequestPermission = useCallback(
|
|
33
|
+
async (permission: OwnCapability) => {
|
|
34
|
+
if (!call?.permissionsContext.canRequest(permission)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
setIsAwaitingApproval(true);
|
|
38
|
+
try {
|
|
39
|
+
await call.requestPermissions({ permissions: [permission] });
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof AxiosError) {
|
|
42
|
+
console.log(
|
|
43
|
+
'RequestPermissions failed',
|
|
44
|
+
error.response?.data.message,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
[call],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
usePermissionNotification({
|
|
53
|
+
permission: OwnCapability.SEND_VIDEO,
|
|
54
|
+
messageApproved: 'You can now share your video.',
|
|
55
|
+
messageRevoked: 'You can no longer share your video.',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const handleToggleVideoButton = async () => {
|
|
59
|
+
if (userHasSendVideoCapability) {
|
|
60
|
+
await toggleVideoMuted();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!isAwaitingApproval) {
|
|
64
|
+
await handleRequestPermission(OwnCapability.SEND_VIDEO);
|
|
65
|
+
} else {
|
|
66
|
+
Alert.alert('Awaiting for an approval to share your video.');
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Restricted requiredGrants={[OwnCapability.SEND_VIDEO]}>
|
|
72
|
+
<CallControlsButton
|
|
73
|
+
onPress={handleToggleVideoButton}
|
|
74
|
+
color={muteStatusColor(isVideoMuted)}
|
|
75
|
+
style={!isVideoMuted ? styles.button : null}
|
|
76
|
+
>
|
|
77
|
+
{isVideoMuted ? (
|
|
78
|
+
<VideoSlash color={theme.light.static_white} />
|
|
79
|
+
) : (
|
|
80
|
+
<Video color={theme.light.static_black} />
|
|
81
|
+
)}
|
|
82
|
+
</CallControlsButton>
|
|
83
|
+
</Restricted>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const styles = StyleSheet.create({
|
|
88
|
+
button: {
|
|
89
|
+
// For iOS
|
|
90
|
+
shadowOffset: {
|
|
91
|
+
width: 0,
|
|
92
|
+
height: 6,
|
|
93
|
+
},
|
|
94
|
+
shadowOpacity: 0.37,
|
|
95
|
+
shadowRadius: 7.49,
|
|
96
|
+
|
|
97
|
+
// For android
|
|
98
|
+
elevation: 6,
|
|
99
|
+
},
|
|
100
|
+
svgContainerStyle: {
|
|
101
|
+
paddingTop: theme.padding.xs,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Image, Platform, StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
import { generateCallTitle } from '../utils';
|
|
4
|
+
import {
|
|
5
|
+
useCallMembers,
|
|
6
|
+
useConnectedUser,
|
|
7
|
+
} from '@stream-io/video-react-bindings';
|
|
8
|
+
import { UserResponse } from '@stream-io/video-client';
|
|
9
|
+
import { theme } from '../theme';
|
|
10
|
+
|
|
11
|
+
enum AvatarModes {
|
|
12
|
+
small = 'sm',
|
|
13
|
+
medium = 'md',
|
|
14
|
+
large = 'lg',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type UserInfoViewType = {
|
|
18
|
+
/**
|
|
19
|
+
* Whether to include the current user in the list of members to show.
|
|
20
|
+
* @default false.
|
|
21
|
+
*/
|
|
22
|
+
includeSelf?: boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The maximum number of members to show.
|
|
26
|
+
* @default 3.
|
|
27
|
+
*/
|
|
28
|
+
totalMembersToShow?: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const UserInfoView = ({
|
|
32
|
+
includeSelf = false,
|
|
33
|
+
totalMembersToShow = 3,
|
|
34
|
+
}: UserInfoViewType) => {
|
|
35
|
+
const connectedUser = useConnectedUser();
|
|
36
|
+
const members = useCallMembers();
|
|
37
|
+
|
|
38
|
+
// take the first N members to show their avatars
|
|
39
|
+
const membersToShow: UserResponse[] = (members || [])
|
|
40
|
+
.slice(0, totalMembersToShow)
|
|
41
|
+
.map(({ user }) => user)
|
|
42
|
+
.filter((user) => user.id !== connectedUser?.id ?? includeSelf);
|
|
43
|
+
if (
|
|
44
|
+
includeSelf &&
|
|
45
|
+
!membersToShow.find((user) => user.id === connectedUser?.id)
|
|
46
|
+
) {
|
|
47
|
+
// if the current user is not in the initial batch of members,
|
|
48
|
+
// add it to the beginning of the list
|
|
49
|
+
const self = members.find(({ user }) => user.id === connectedUser?.id);
|
|
50
|
+
if (self) {
|
|
51
|
+
membersToShow.splice(0, 1, self.user);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const memberUserIds = membersToShow.map(
|
|
56
|
+
(memberToShow) => memberToShow.name ?? memberToShow.id,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const callTitle = generateCallTitle(memberUserIds, totalMembersToShow);
|
|
60
|
+
|
|
61
|
+
const avatarSizeModes: { [key: number]: AvatarModes } = {
|
|
62
|
+
1: AvatarModes.large,
|
|
63
|
+
2: AvatarModes.medium,
|
|
64
|
+
3: AvatarModes.small,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const mode = avatarSizeModes[memberUserIds.length] || AvatarModes.small;
|
|
68
|
+
|
|
69
|
+
const avatarStyles = {
|
|
70
|
+
height: theme.avatar[mode],
|
|
71
|
+
width: theme.avatar[mode],
|
|
72
|
+
borderRadius: theme.avatar[mode] / 2,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const fontStyleByMembersCount =
|
|
76
|
+
memberUserIds.length > 1 ? theme.fonts.heading5 : theme.fonts.heading4;
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<View style={styles.userInfo}>
|
|
80
|
+
<View style={styles.avatarGroup}>
|
|
81
|
+
{membersToShow.map((memberToShow) => {
|
|
82
|
+
return (
|
|
83
|
+
<Image
|
|
84
|
+
key={memberToShow.id}
|
|
85
|
+
style={[avatarStyles]}
|
|
86
|
+
// FIXME: use real avatar from coordinator this is temporary
|
|
87
|
+
source={{
|
|
88
|
+
uri: memberToShow.image,
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
})}
|
|
93
|
+
</View>
|
|
94
|
+
<Text style={[styles.name, fontStyleByMembersCount]}>{callTitle}</Text>
|
|
95
|
+
</View>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const styles = StyleSheet.create({
|
|
100
|
+
userInfo: {
|
|
101
|
+
paddingHorizontal:
|
|
102
|
+
Platform.OS === 'android' ? theme.padding.xl * 4 : theme.padding.xl * 2,
|
|
103
|
+
display: 'flex',
|
|
104
|
+
flexDirection: 'column',
|
|
105
|
+
justifyContent: 'space-between',
|
|
106
|
+
},
|
|
107
|
+
avatarGroup: {
|
|
108
|
+
display: 'flex',
|
|
109
|
+
flexDirection: 'row',
|
|
110
|
+
justifyContent: 'space-evenly',
|
|
111
|
+
flexWrap: 'wrap',
|
|
112
|
+
},
|
|
113
|
+
name: {
|
|
114
|
+
color: theme.light.static_white,
|
|
115
|
+
textAlign: 'center',
|
|
116
|
+
marginTop: theme.margin.xl,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { MediaStream, RTCView } from 'react-native-webrtc';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Props to be passed for the VideoRenderer component.
|
|
7
|
+
*/
|
|
8
|
+
export interface VideoRendererProps {
|
|
9
|
+
/**
|
|
10
|
+
* The stream that should be rendered.
|
|
11
|
+
*/
|
|
12
|
+
mediaStream: MediaStream;
|
|
13
|
+
/**
|
|
14
|
+
* Indicates whether the video should be
|
|
15
|
+
* mirrored during rendering. Commonly, applications choose to mirror the
|
|
16
|
+
* user-facing camera.
|
|
17
|
+
*
|
|
18
|
+
* @defaultValue
|
|
19
|
+
* The default is `false`
|
|
20
|
+
*/
|
|
21
|
+
mirror?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Similarly to the CSS property z-index, specifies the z-order of this
|
|
24
|
+
* `RTCView` in the stacking space of all `RTCView`s. When `RTCView`s overlap,
|
|
25
|
+
* `zOrder` determines which one covers the other. An `RTCView` with a larger
|
|
26
|
+
* `zOrder` generally covers an RTCView with a lower one.
|
|
27
|
+
*
|
|
28
|
+
* Non-overlapping `RTCView`s may safely share a z-order (because one does not
|
|
29
|
+
* have to cover the other).
|
|
30
|
+
*
|
|
31
|
+
* The support for `zOrder` is platform-dependent and/or
|
|
32
|
+
* implementation-specific. Thus, specifying a value for `zOrder` is to be
|
|
33
|
+
* thought of as giving a hint rather than as imposing a requirement. For
|
|
34
|
+
* example, video renderers such as `RTCView` are commonly implemented using
|
|
35
|
+
* OpenGL and OpenGL views may have different numbers of layers in their
|
|
36
|
+
* stacking space. android has three: a layer bellow the window (aka
|
|
37
|
+
* default), a layer bellow the window again but above the previous layer
|
|
38
|
+
* (aka media overlay), and above the window. Consequently, it is advisable
|
|
39
|
+
* to limit the number of utilized layers in the stacking space to the
|
|
40
|
+
* minimum sufficient for the desired display. For example, a video call
|
|
41
|
+
* application usually needs a maximum of two `zOrder` values: 0 for the
|
|
42
|
+
* remote one or more videos which appear in the background, and 1 for the local
|
|
43
|
+
* one or more videos which appear above the remote one or more videos.
|
|
44
|
+
*/
|
|
45
|
+
zOrder?: number;
|
|
46
|
+
/**
|
|
47
|
+
* In the fashion of
|
|
48
|
+
* https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth
|
|
49
|
+
* and https://www.w3.org/TR/html5/rendering.html#video-object-fit,
|
|
50
|
+
* resembles the CSS style object-fit.
|
|
51
|
+
*
|
|
52
|
+
* @defaultValue
|
|
53
|
+
* The default is `cover`
|
|
54
|
+
*/
|
|
55
|
+
objectFit?: 'contain' | 'cover';
|
|
56
|
+
/**
|
|
57
|
+
* Style to override the default style of the `RTCView`.
|
|
58
|
+
* @defaultValue
|
|
59
|
+
* The default is `{ flex: 1 }`
|
|
60
|
+
*/
|
|
61
|
+
style?: StyleProp<ViewStyle>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Lower level component, that represents only the video part (wrapper around the WebRTC)
|
|
66
|
+
* //Todo: SG: add photo's with all states
|
|
67
|
+
*/
|
|
68
|
+
export const VideoRenderer = (props: VideoRendererProps) => {
|
|
69
|
+
const {
|
|
70
|
+
mediaStream,
|
|
71
|
+
mirror = false,
|
|
72
|
+
style = { flex: 1 },
|
|
73
|
+
zOrder = undefined,
|
|
74
|
+
objectFit = 'cover',
|
|
75
|
+
} = props;
|
|
76
|
+
return (
|
|
77
|
+
<RTCView
|
|
78
|
+
streamURL={mediaStream?.toURL()}
|
|
79
|
+
mirror={mirror}
|
|
80
|
+
style={style}
|
|
81
|
+
objectFit={objectFit}
|
|
82
|
+
zOrder={zOrder}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './ActiveCall';
|
|
2
|
+
export * from './IncomingCallView';
|
|
3
|
+
export * from './OutgoingCallView';
|
|
4
|
+
export * from './Avatar';
|
|
5
|
+
export * from './VideoRenderer';
|
|
6
|
+
export * from './LocalVideoView';
|
|
7
|
+
export * from './ParticipantView';
|
|
8
|
+
export * from './CallParticipantsView';
|
|
9
|
+
export * from './CallControlsView';
|
|
10
|
+
export * from './CallParticipantsInfoView';
|
|
11
|
+
export * from './LobbyView';
|
|
12
|
+
export * from './ReactionsModal';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export enum A11yIcons {
|
|
2
|
+
MUTED_VIDEO = 'muted-video-icon',
|
|
3
|
+
HANG_UP_CALL = 'hang-up-call-icon',
|
|
4
|
+
SCREEN_SHARE = 'screen-share-icon',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum A11yComponents {
|
|
8
|
+
PARTICIPANT_AVATAR = 'participant-avatar',
|
|
9
|
+
CALL_PARTICIPANTS_LIST = 'call-participants-list',
|
|
10
|
+
LOCAL_PARTICIPANT = 'local-participant',
|
|
11
|
+
PARTICIPANT_MEDIA_STREAM = 'participant-media-stream',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export enum A11yButtons {
|
|
15
|
+
PARTICIPANTS_INFO = 'participants-info-button',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum A11yValues {
|
|
19
|
+
PARTICIPANTS_IS_SPEAKING = 'participant-is-speaking',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export enum A11yImages {
|
|
23
|
+
AVATAR = 'avatar-image',
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { theme } from '../theme';
|
|
2
|
+
|
|
3
|
+
export const LOCAL_VIDEO_VIEW_STYLE = {
|
|
4
|
+
height: 140,
|
|
5
|
+
width: 80,
|
|
6
|
+
borderRadius: theme.rounded.sm,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const defaultEmojiReactions = [
|
|
10
|
+
{
|
|
11
|
+
type: 'reaction',
|
|
12
|
+
emoji_code: ':like:',
|
|
13
|
+
custom: {},
|
|
14
|
+
icon: '👍',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
type: 'raised-hand',
|
|
18
|
+
emoji_code: ':raise-hand:',
|
|
19
|
+
custom: {},
|
|
20
|
+
icon: '✋',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: 'reaction',
|
|
24
|
+
emoji_code: ':fireworks:',
|
|
25
|
+
custom: {},
|
|
26
|
+
icon: '🎉',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
8
|
+
|
|
9
|
+
export default function createStoreContext<PassedStoreType extends object>(
|
|
10
|
+
initialState: PassedStoreType,
|
|
11
|
+
) {
|
|
12
|
+
type SetStateFuncType = (
|
|
13
|
+
partialStateOrFunc:
|
|
14
|
+
| Partial<StoreType>
|
|
15
|
+
| ((prevState: StoreType) => Partial<PassedStoreType>),
|
|
16
|
+
) => void;
|
|
17
|
+
|
|
18
|
+
// returns unsubscribe function
|
|
19
|
+
type SubscribeFunc = (callback: () => void) => () => void;
|
|
20
|
+
|
|
21
|
+
type StoreType = PassedStoreType & { isStoreInitialized: boolean };
|
|
22
|
+
|
|
23
|
+
function useStoreData(): {
|
|
24
|
+
getSnapshot: () => StoreType;
|
|
25
|
+
setState: SetStateFuncType;
|
|
26
|
+
subscribe: SubscribeFunc;
|
|
27
|
+
} {
|
|
28
|
+
const storeRef = useRef<StoreType>({
|
|
29
|
+
...initialState,
|
|
30
|
+
isStoreInitialized: false,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const getSnapshot = useRef(() => storeRef.current).current;
|
|
34
|
+
|
|
35
|
+
const subscribersRef = useRef<(() => void)[]>([]);
|
|
36
|
+
|
|
37
|
+
const setState = useRef<SetStateFuncType>((partialStateOrFunc) => {
|
|
38
|
+
if (typeof partialStateOrFunc === 'function') {
|
|
39
|
+
const value = partialStateOrFunc(storeRef.current);
|
|
40
|
+
storeRef.current = {
|
|
41
|
+
...storeRef.current,
|
|
42
|
+
...value,
|
|
43
|
+
};
|
|
44
|
+
} else {
|
|
45
|
+
storeRef.current = { ...storeRef.current, ...partialStateOrFunc };
|
|
46
|
+
}
|
|
47
|
+
subscribersRef.current.forEach((callback) => callback());
|
|
48
|
+
}).current;
|
|
49
|
+
|
|
50
|
+
const subscribe = useRef((callback: () => void) => {
|
|
51
|
+
subscribersRef.current.push(callback);
|
|
52
|
+
return () => subscribersRef.current.filter((cb) => cb !== callback);
|
|
53
|
+
}).current;
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
getSnapshot,
|
|
57
|
+
setState,
|
|
58
|
+
subscribe,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type HookReturnType = ReturnType<typeof useStoreData>;
|
|
63
|
+
|
|
64
|
+
const StoreContext = createContext<HookReturnType | null>(null);
|
|
65
|
+
|
|
66
|
+
function Provider(props: React.PropsWithChildren<{}>) {
|
|
67
|
+
const value = useStoreData();
|
|
68
|
+
return (
|
|
69
|
+
<StoreContext.Provider value={value}>
|
|
70
|
+
{props.children}
|
|
71
|
+
</StoreContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param selector
|
|
77
|
+
* @returns
|
|
78
|
+
*
|
|
79
|
+
* @category Client State
|
|
80
|
+
*/
|
|
81
|
+
function useStoreValue<SelectorOutput extends StoreType[keyof StoreType]>(
|
|
82
|
+
selector: (store: StoreType) => SelectorOutput,
|
|
83
|
+
): SelectorOutput {
|
|
84
|
+
const store = useContext(StoreContext);
|
|
85
|
+
if (!store) {
|
|
86
|
+
throw new Error('Store not found');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const [state, setState] = useState(selector(store.getSnapshot()));
|
|
90
|
+
useEffect(
|
|
91
|
+
() => store.subscribe(() => setState(selector(store.getSnapshot()))),
|
|
92
|
+
[selector, store],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return state;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
*
|
|
100
|
+
* @returns
|
|
101
|
+
*
|
|
102
|
+
* @category Client State
|
|
103
|
+
*/
|
|
104
|
+
function useStoreSetState() {
|
|
105
|
+
const store = useContext(StoreContext);
|
|
106
|
+
if (!store) {
|
|
107
|
+
throw new Error('Store not found');
|
|
108
|
+
}
|
|
109
|
+
return store.setState;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
Provider,
|
|
114
|
+
useStoreValue,
|
|
115
|
+
useStoreSetState,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import createStoreContext from './createStoreContext';
|
|
2
|
+
|
|
3
|
+
export type MediaDeviceInfo = {
|
|
4
|
+
deviceId: string;
|
|
5
|
+
facing?: 'environment' | 'front';
|
|
6
|
+
groupId: string;
|
|
7
|
+
kind: 'videoinput' | 'audioinput';
|
|
8
|
+
label: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Exclude types from documentation site, but we should still add doc comments
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export interface SDKStreamVideoStore {
|
|
16
|
+
isCameraOnFrontFacingMode: boolean;
|
|
17
|
+
isVideoMuted: boolean;
|
|
18
|
+
isAudioMuted: boolean;
|
|
19
|
+
currentAudioDevice?: MediaDeviceInfo;
|
|
20
|
+
currentVideoDevice?: MediaDeviceInfo;
|
|
21
|
+
audioDevices: MediaDeviceInfo[];
|
|
22
|
+
videoDevices: MediaDeviceInfo[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const {
|
|
26
|
+
Provider: StreamVideoStoreProvider,
|
|
27
|
+
useStoreValue: useStreamVideoStoreValue,
|
|
28
|
+
useStoreSetState: useStreamVideoStoreSetState,
|
|
29
|
+
} = createStoreContext<SDKStreamVideoStore>({
|
|
30
|
+
isCameraOnFrontFacingMode: false,
|
|
31
|
+
isVideoMuted: false,
|
|
32
|
+
isAudioMuted: false,
|
|
33
|
+
videoDevices: [],
|
|
34
|
+
audioDevices: [],
|
|
35
|
+
currentVideoDevice: undefined,
|
|
36
|
+
currentAudioDevice: undefined,
|
|
37
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StreamVideoContext';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './useCallControls';
|
|
2
|
+
export * from './useCallCycleEffect';
|
|
3
|
+
export * from './useMutingState';
|
|
4
|
+
export * from './useLocalVideoStream';
|
|
5
|
+
export * from './useCallKeep';
|
|
6
|
+
export * from './useIncallManager';
|
|
7
|
+
export * from './usePublishMediaStreams';
|
|
8
|
+
export * from './usePermissionRequest';
|
|
9
|
+
export * from './usePermissionNotification';
|
|
10
|
+
export * from './useCreateStreamVideoClient';
|