UNPKG

@100mslive/react-native-room-kit

Version:

100ms Room Kit provides simple & easy to use UI components to build Live Streaming & Video Conferencing experiences in your apps.

355 lines (352 loc) 11.3 kB
import * as React from 'react'; import { Image, Text, View, ScrollView, StyleSheet, TouchableOpacity, ActivityIndicator } from 'react-native'; import { useDispatch, useSelector } from 'react-redux'; import { HMSTrackType, HMSVideoViewMode } from '@100mslive/react-native-hms'; import { ImagePicker } from '../modules/imagePickerWrapper'; import { BottomSheet } from './BottomSheet'; import { AddImageIcon, BlurPeopleIcon, CloseIcon, CrossCircleIcon } from '../Icons'; import { useDisableAutoPip, useHMSRoomColorPalette, useHMSRoomStyleSheet } from '../hooks-util'; import { VideoView } from './PeerVideoTile/VideoView'; import { setAutoEnterPipMode, setSelectedVirtualBackground } from '../redux/actions'; import { useState } from 'react'; import { hexToRgbA } from '../utils/theme'; export const VirtualBackgroundModalContent = ({ dismissModal }) => { const dispatch = useDispatch(); const localPeer = useSelector(state => state.hmsStates.localPeer); const isLocalVideoMuted = useSelector(state => state.hmsStates.isLocalVideoMuted); const autoEnterPipMode = useSelector(state => state.app.autoEnterPipMode); const disableAutoPip = useDisableAutoPip(); const hmsRoomStyles = useHMSRoomStyleSheet((theme, typography) => ({ semiBoldSurfaceHigh: { color: theme.palette.on_surface_high, fontFamily: `${typography.font_family}-SemiBold` }, regularSurfaceMedium: { color: theme.palette.on_surface_medium, fontFamily: `${typography.font_family}-Regular` }, effectButton: { backgroundColor: theme.palette.surface_bright }, active: { borderColor: theme.palette.primary_default }, inactive: { borderColor: theme.palette.surface_bright }, loadingContainer: { backgroundColor: theme.palette.background_default && hexToRgbA(theme.palette.background_default, 0.5) } })); const { primary_bright: primaryBrightColor } = useHMSRoomColorPalette(); const videoPlugin = useSelector(state => state.hmsStates.videoPlugin); const selectedVirtualBG = useSelector(state => state.app.selectedVirtualBackground); const handleClosePress = () => dismissModal(); const handleNoEffectPress = async () => { if (videoPlugin) { await videoPlugin.disable(); dispatch(setSelectedVirtualBackground(null)); } }; const [showLoading, setShowLoading] = useState(false); const handlePhotoLibraryPress = async () => { if (!ImagePicker) { return; } // Current value of `autoEnterPipMode` state let pipModeEnabled = autoEnterPipMode; try { // If PIP is enabled, disable it if (pipModeEnabled) { dispatch(setAutoEnterPipMode(false)); disableAutoPip({}); } const imageLibraryResponse = await ImagePicker.launchImageLibrary({ mediaType: 'photo', selectionLimit: 1 }); // If PIP was enabled earlier, enable it again if (pipModeEnabled) { dispatch(setAutoEnterPipMode(true)); } handleImagePickerResponse(imageLibraryResponse); } catch (error) { console.warn(error); } }; // const handleCameraPress = async () => { // if (!ImagePicker) { // return; // } // try { // const cameraResponse = await ImagePicker.launchCamera({ // mediaType: 'photo', // cameraType: 'back', // }); // handleImagePickerResponse(cameraResponse); // } catch (error) { // console.warn(error); // } // }; const handleImagePickerResponse = response => { var _response$assets; if (response.didCancel) { throw new Error('User cancelled'); } if (response.errorCode !== undefined) { throw new Error(response.errorCode, { cause: response.errorMessage }); } const firstAsset = (_response$assets = response.assets) === null || _response$assets === void 0 ? void 0 : _response$assets[0]; if (firstAsset && firstAsset.uri && firstAsset.fileName) { handleImagePress({ label: firstAsset.fileName, src: firstAsset }); } }; const handleBlurEffectPress = async () => { try { if (videoPlugin) { setShowLoading(true); if (selectedVirtualBG === null) { await videoPlugin.enable(); } await videoPlugin.setBlur(100); setShowLoading(false); dispatch(setSelectedVirtualBackground('blur')); } } catch (error) { setShowLoading(false); console.error('Error setting blur effect', error); } }; const handleImagePress = async asset => { try { if (videoPlugin) { setShowLoading(true); if (selectedVirtualBG === null) { await videoPlugin.enable(); } await videoPlugin.setBackground(asset.src); setShowLoading(false); dispatch(setSelectedVirtualBackground(asset.label)); } } catch (error) { setShowLoading(false); console.error('Error setting virtual background', error); } }; const showingVideoTrack = localPeer && localPeer.videoTrack && localPeer.videoTrack.trackId && localPeer.videoTrack.type === HMSTrackType.VIDEO && !isLocalVideoMuted; const backgrounds = []; if (ImagePicker) { // backgrounds.push({ // label: 'Camera', // onPress: handleCameraPress, // }); backgrounds.push({ icon: /*#__PURE__*/React.createElement(AddImageIcon, null), label: 'Upload', onPress: handlePhotoLibraryPress }); } return /*#__PURE__*/React.createElement(View, { style: styles.flexView }, /*#__PURE__*/React.createElement(View, { style: styles.header }, /*#__PURE__*/React.createElement(Text, { style: [styles.headerText, hmsRoomStyles.semiBoldSurfaceHigh] }, "Virtual Background"), /*#__PURE__*/React.createElement(TouchableOpacity, { onPress: handleClosePress, hitSlop: styles.closeIconHitSlop, style: styles.closeIconButton }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(BottomSheet.Divider, { style: styles.divider }), /*#__PURE__*/React.createElement(View, { style: styles.flexView }, showingVideoTrack ? /*#__PURE__*/React.createElement(View, { style: { height: 280, alignItems: 'center', marginTop: 32 } }, /*#__PURE__*/React.createElement(View, { style: { width: 166, height: 280 } }, /*#__PURE__*/React.createElement(VideoView, { peer: localPeer, trackId: localPeer.videoTrack.trackId, scaleType: HMSVideoViewMode.ASPECT_FILL }))) : null, /*#__PURE__*/React.createElement(ScrollView, { style: styles.scrollView, contentContainerStyle: styles.scrollContent }, /*#__PURE__*/React.createElement(View, { style: { marginHorizontal: 24 } }, /*#__PURE__*/React.createElement(Text, { style: [hmsRoomStyles.semiBoldSurfaceHigh, styles.normalText] }, "Effects"), /*#__PURE__*/React.createElement(View, { style: { flexDirection: 'row' } }, /*#__PURE__*/React.createElement(TouchableOpacity, { activeOpacity: 0.8, onPress: handleNoEffectPress }, /*#__PURE__*/React.createElement(View, { style: [styles.effectButton, hmsRoomStyles.effectButton, selectedVirtualBG === null ? hmsRoomStyles.active : hmsRoomStyles.inactive] }, /*#__PURE__*/React.createElement(CrossCircleIcon, { size: "large", style: { marginBottom: 8 } }), /*#__PURE__*/React.createElement(Text, { style: [styles.smallText, hmsRoomStyles.regularSurfaceMedium] }, "No Effect"))), /*#__PURE__*/React.createElement(TouchableOpacity, { activeOpacity: 0.8, style: styles.horizontalSpacing, onPress: handleBlurEffectPress }, /*#__PURE__*/React.createElement(View, { style: [styles.effectButton, hmsRoomStyles.effectButton, selectedVirtualBG === 'blur' ? hmsRoomStyles.active : hmsRoomStyles.inactive] }, /*#__PURE__*/React.createElement(BlurPeopleIcon, { style: { marginBottom: 8 } }), /*#__PURE__*/React.createElement(Text, { style: [styles.smallText, hmsRoomStyles.regularSurfaceMedium] }, "Blur"))))), backgrounds && backgrounds.length > 0 ? /*#__PURE__*/React.createElement(View, { style: styles.backgroundContainer }, /*#__PURE__*/React.createElement(Text, { style: [hmsRoomStyles.semiBoldSurfaceHigh, styles.normalText, { marginHorizontal: 24 }] }, "Backgrounds"), /*#__PURE__*/React.createElement(View, { style: [styles.backgroundImages, { marginHorizontal: 18 }] }, backgrounds.map(asset => { return /*#__PURE__*/React.createElement(TouchableOpacity, { key: asset.label, activeOpacity: 0.8, onPress: () => { const src = asset.src; if (src) { handleImagePress({ label: asset.label, src }); } else if (asset.onPress) { asset.onPress(); } }, style: asset.src ? styles.backgroundImageContainer : [styles.effectButton, hmsRoomStyles.effectButton, hmsRoomStyles.inactive, styles.backgroundImageContainer] }, asset.src ? /*#__PURE__*/React.createElement(Image, { source: asset.src, style: [styles.backgroundImage, selectedVirtualBG === asset.label ? hmsRoomStyles.active : null] }) : /*#__PURE__*/React.createElement(React.Fragment, null, asset.icon || null, /*#__PURE__*/React.createElement(Text, { style: [styles.smallText, hmsRoomStyles.regularSurfaceMedium] }, asset.label))); }))) : null), showLoading && /*#__PURE__*/React.createElement(View, { style: [styles.loadingContainer, hmsRoomStyles.loadingContainer] }, /*#__PURE__*/React.createElement(ActivityIndicator, { size: "large", color: primaryBrightColor })))); }; const styles = StyleSheet.create({ // Header header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 16, marginHorizontal: 24 }, headerText: { fontSize: 16, lineHeight: 24, letterSpacing: 0.15 }, closeIconButton: { marginLeft: 16 }, closeIconHitSlop: { bottom: 16, left: 16, right: 16, top: 16 }, // Divider divider: { marginVertical: 0, marginTop: 16 }, // Content flexView: { flex: 1, position: 'relative' }, scrollView: { marginTop: 16 }, scrollContent: { paddingTop: 8, paddingBottom: 24 }, normalText: { fontSize: 14, lineHeight: 20, marginBottom: 8 }, smallText: { fontSize: 12, lineHeight: 16, letterSpacing: 0.4 }, effectButton: { width: 104, height: 88, borderRadius: 8, alignItems: 'center', justifyContent: 'center', borderWidth: 2 }, horizontalSpacing: { marginHorizontal: 12 }, backgroundContainer: { marginTop: 24 }, backgroundImages: { flex: 1, flexDirection: 'row', flexWrap: 'wrap' }, backgroundImage: { width: 104, height: 88, borderRadius: 8, resizeMode: 'cover', borderWidth: 2, borderColor: 'transparent' }, backgroundImageContainer: { marginHorizontal: 6, marginVertical: 8 }, loadingContainer: { width: '100%', height: '100%', position: 'absolute', alignItems: 'center', justifyContent: 'center' } }); //# sourceMappingURL=VirtualBackgroundModalContent.js.map