@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
JavaScript
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