@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
JavaScript
/*
* 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);