UNPKG

@applicaster/zapp-react-native-utils

Version:

Applicaster Zapp React Native utilities package

198 lines (169 loc) • 5.61 kB
/// <reference types="@types/react-native" /> import * as ReactNative from "react-native"; import { isTV, platformSelect } from "../reactUtils"; import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks"; import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks"; import { QUICK_BRICK_EVENTS, QuickBrickEvent, sendQuickBrickEvent, } from "@applicaster/zapp-react-native-bridge/QuickBrick"; import { utilsLogger } from "../logger"; const { DeviceEventEmitter, NativeModules, NativeEventEmitter } = ReactNative; // simply evaluating new NativeEventEmitter(NativeModules.ReactNativeEventEmitter) // will cause the native code to crash on tvOS, even if it's not the selected platform const EventEmitter = platformSelect({ android: DeviceEventEmitter, ios: isTV() ? DeviceEventEmitter : new NativeEventEmitter(NativeModules.ReactNativeEventEmitter), default: DeviceEventEmitter, }); const logger = utilsLogger.addSubsystem("orientationHelper"); /** * @enum {Orientations} */ export enum ORIENTATIONS { unknown = 0, portrait = 1, landscapeRight = 2, landscapeLeft = 4, landscapeSensor = 6, allButUpsideDown = 7, portraitUpsideDown = 8, all = 15, } export const ORIENTATIONS_BUILDER = { toString: (orientation: ORIENTATIONS): string => { return ORIENTATIONS[orientation]; }, fromString: (orientation: string): ORIENTATIONS => { return (ORIENTATIONS as any)[orientation]; }, }; export function getOrientation(orientation: OrientationTypes): ORIENTATIONS { return ORIENTATIONS[orientation]; } type OrientationListener = (OrientationListenerArgs?) => void; /** * This events sets the allowed screen orientations for current screen * example for portrait and both landscape: allowedOrientationsForScreen(ORIENTATIONS.allButUpsideDown) * (use enum provided in this module) * Example of forcing landscape right: allowedOrientationsForScreen(ORIENTATIONS.landscapeRight) * (use enum provided in this module) * @param {OrientationTypes} orientation - Allowed orientations */ export const allowedOrientationsForScreen = ( orientation: ORIENTATIONS ): void => { logger.debug({ message: `allowedOrientationsForScreen: new orientation: ${ORIENTATIONS[orientation]}`, }); sendQuickBrickEvent( QUICK_BRICK_EVENTS.ALLOWED_ORIENTATIONS_FOR_SCREEN as QuickBrickEvent, { orientation, } ); }; /** * * @callback orientationChangeCallback * @param {Object}: response * @param {Orientations}: response.toOrientation - Current orientation * @param {Orientations}: response.fromOrientation - Previous orientation */ /** * Sets and return orientationChange listener * @param {orientationChangeCallback} callback - called on orientation change with the new and old orientation * @return {*} - orientationChange Listener instance */ export const addOrientationChangeListener = ( callback: OrientationListener ): any => { try { if (isTV()) () => {}; return EventEmitter.addListener("orientationChange", callback); } catch (err) { logger.error(err); } }; /** * Removes listener by calling remove method on the provided orientationChange listener instance * @param {*} listener - orientationChange listener instance */ export const removeOrientationChangeListener = (listener: any): void => { try { listener.remove(); } catch (err) { logger.error(err); } }; /** * Returns true if current screen aspect is compatible with required screen orientation. * Uses provided device screen dimensions since RN hooks orientation state takes time to update. * TODO: use `current` of orientationHandler.ts */ export const isOrientationCompatible = ({ orientation, layoutData: { width, height }, }) => { const isLandscape = width > height; if ( [ORIENTATIONS.portrait, ORIENTATIONS.portraitUpsideDown].includes( orientation ) ) { return !isLandscape; } if ( [ ORIENTATIONS.landscapeLeft, ORIENTATIONS.landscapeRight, ORIENTATIONS.landscapeSensor, ].includes(orientation) ) { return isLandscape; } return true; }; export const useIsOrientationCompatible = (orientation) => { const { height, width } = ReactNative.useWindowDimensions(); return isOrientationCompatible({ orientation, layoutData: { width, height }, }); }; /** * Determine final screen orientation based on device type, * settings and orientation value provided by screen data settings */ export const getScreenOrientation = ({ screenData, layoutData: { isTablet, isTabletPortrait }, }) => { const isLandscapeTablet = isTablet && !isTabletPortrait; if (isLandscapeTablet) { return ORIENTATIONS.landscapeSensor; } /** * HACK: Warning * screenData?.targetScreen?.general?.screen_orientation for player plugins is hardcoded inside NavigationProvider's * method called legacyScreenData. Check it for more details about the hack. */ const orientation = screenData?.targetScreen?.general?.screen_orientation || screenData?.general?.screen_orientation; const screenOrientation = getOrientation(orientation); // TODO: Maybe return null if screen does not specify desired orientation (i.e. works on both)? return screenOrientation || ORIENTATIONS.portrait; }; export const useGetScreenOrientation = (screenData) => { const isTablet = useIsTablet(); const { appData } = usePickFromState(["appData"]); const isTabletPortrait = appData?.isTabletPortrait; return getScreenOrientation({ screenData, layoutData: { isTablet, isTabletPortrait }, }); };