UNPKG

@s20.ai/safecam-360-rn-lite

Version:

A React Native component to view the interior panorama and exterior 360 degree views of a product featuring suppport for hotspots. Compatible with Android and iOS

244 lines (224 loc) 8.18 kB
/* * Copyright © 2022 S20.AI India Pvt. Ltd. * Contact - origin@s20.ai * License - Licensed as per https://docs.s20.ai/license.html */ import React, {useEffect, useRef} from 'react'; import {View, Dimensions, LogBox, AppState} from 'react-native'; import Interior360 from './interior/Interior360'; import Exterior360 from './exterior/Exterior360PanResp'; import {connect} from 'react-redux'; import { setCurrentOrientation, setWidgetsVisible, } from '../redux/actions/currentViewAction'; import {useDispatch} from 'react-redux'; import constants from '../config/constants'; import HotspotOverlay from './hotspot/HotspotOverlay'; import {preProcess} from '../utils/propsPreprocessing'; import Orientation from 'react-native-orientation-locker'; import appStyleConfig from '../components/appStyleConfig'; import {getOrientation} from '../utils/device'; import WidgetOverlay from './widgets/WidgetOverlay'; import {SafeAreaProvider} from 'react-native-safe-area-context'; LogBox.ignoreLogs(['new NativeEventEmitter']); const window = Dimensions.get('window'); const width = window.width; const height = window.height; let orientationTimeout = null; const MainWrapper = ({ currentViewState, interiorData, exteriorData, currentHotspotState, widgetsVisible, orientationState, enableHotspots, enableGalleryButton, enableHotspotTooltip, galleryButtonPressed, enableBackButton, backButtonPressed, enableCarAutorotateOnCardSwipe, enableCardSwipeOnCarRotation, bottomToolbarButtonPressed, bottomToolbarSwitchToggled, hotspotPressed, orientationChanged, onInteraction, customInteriorUrl, customFontFamily, exterior360ResizeMode, interior360InitialPosition, customGalleryButton, customBackButton, miniMode, }) => { const [ exteriorDataProcessed, interiorDataProcessed, combinedHotspotMetadata, ] = preProcess(exteriorData, interiorData); const dispatch = useDispatch(); const appState = useRef(AppState.currentState); const handleOrientationChangeAll = async orientation => { if (orientationTimeout) clearTimeout(orientationTimeout); orientationTimeout = setTimeout(() => { if ( orientation && orientation !== constants.UNKNOWN && orientation !== constants.PORTRAIT_UPSIDE_DOWN && orientation !== constants.FACE_UP ) { dispatch(setCurrentOrientation(orientation)); } if (orientationChanged) { //when actual orientation is FACE_UP, android returns UNKNOWN if (orientation === constants.UNKNOWN) { orientationChanged(constants.FACE_UP); } else { orientationChanged(orientation); } } }, 500); }; const handleAppStateChange = nextAppState => { if (appState.current === 'background' && nextAppState === 'active') { //required incase someone puts the viewer in the background on landscape mode and then comes back to the viewer //OR if the component is not unmounted but the app is in the background //failure to do this would result in the orientation being portrait setTimeout(() => { Orientation.unlockAllOrientations(); }, 200); } if ( appState.current.match(/inactive|background/) && nextAppState === 'active' ) { // console.log("App has come to the foreground!"); } appState.current = nextAppState; }; useEffect(() => { //Required to get initial orientation - listener won't be fired if the view loads in landscape by default Orientation.getDeviceOrientation(orientation => { if ( orientation && (orientation.includes(constants.PORTRAIT) || orientation.includes(constants.LANDSCAPE)) ) { dispatch(setCurrentOrientation(orientation)); if (orientationChanged) { orientationChanged(orientation); } } else { //TODO - extra work may be required //Fallback incase no orientation or Orientation = UNKNOWN is returned if (Orientation.getInitialOrientation()) { dispatch(setCurrentOrientation(Orientation.getInitialOrientation())); if (orientationChanged) { orientationChanged(Orientation.getInitialOrientation()); } } else { dispatch(setCurrentOrientation(getOrientation())); if (orientationChanged) { orientationChanged(getOrientation()); } } } }); Orientation.unlockAllOrientations(); Orientation.addDeviceOrientationListener(handleOrientationChangeAll); const appStateSubscription = AppState.addEventListener( 'change', handleAppStateChange, ); return () => { Orientation.removeAllListeners(); appStateSubscription.remove(); }; }, []); useEffect(() => { if (currentHotspotState) { dispatch(setWidgetsVisible(false)); } else { dispatch(setWidgetsVisible(true)); } }, [currentHotspotState]); return ( <SafeAreaProvider> <View style={appStyleConfig.mainWrapperContainer}> {Object.keys(exteriorDataProcessed).length > 0 && ( <Exterior360 customFontFamily={customFontFamily} width={width} height={height / 2} srcset={exteriorDataProcessed.imageSource} srcsetCompressed={exteriorDataProcessed.lowResImages} highResImages={exteriorDataProcessed.highResImages} filteredHotspotMetadata={ exteriorDataProcessed.filteredHotspotMetadata } initialFrame={exteriorDataProcessed.initialFrame} hotspots={exteriorDataProcessed.hotspotPostionData} hotspotsParsed={exteriorDataProcessed.hotspotPostionDataParsed} enableHotspots={enableHotspots} enableHotspotTooltip={enableHotspotTooltip} enableCarAutorotateOnCardSwipe={enableCarAutorotateOnCardSwipe} enableCardSwipeOnCarRotation={enableCardSwipeOnCarRotation} hotspotPressed={hotspotPressed} onInteraction={onInteraction} exterior360ResizeMode={exterior360ResizeMode} miniMode={miniMode} /> )} {Object.keys(interiorDataProcessed).length > 0 && ( <Interior360 interiorData={interiorDataProcessed} enableHotspots={enableHotspots} hotspotPressed={hotspotPressed} onInteraction={onInteraction} customInteriorUrl={customInteriorUrl} customFontFamily={customFontFamily} interior360InitialPosition={interior360InitialPosition} miniMode={miniMode} /> )} {currentHotspotState && Object.keys(exteriorDataProcessed).length > 0 && Object.keys(interiorDataProcessed).length > 0 && ( <HotspotOverlay exteriorData={exteriorDataProcessed} interiorData={interiorDataProcessed} customFontFamily={customFontFamily} /> )} <WidgetOverlay galleryButtonPressed={galleryButtonPressed} enableGalleryButton={enableGalleryButton} enableBackButton={enableBackButton} backButtonPressed={backButtonPressed} combinedHotspotMetadata={combinedHotspotMetadata} bottomToolbarButtonPressed={bottomToolbarButtonPressed} bottomToolbarSwitchToggled={bottomToolbarSwitchToggled} exteriorDataProcessed={exteriorDataProcessed} interiorDataProcessed={interiorDataProcessed} enableHotspots={enableHotspots} customFontFamily={customFontFamily} customGalleryButton={customGalleryButton} customBackButton={customBackButton} miniMode={miniMode} /> </View> </SafeAreaProvider> ); }; const mapStateToProps = ({currentView, currentHotspot}) => { return { currentViewState: currentView.present, orientationState: currentView.orientation, widgetsVisible: currentView.widgetsVisible, currentHotspotState: currentHotspot, }; }; export default connect(mapStateToProps)(MainWrapper);