import React, { useMemo } from "react"; import { Animated, Dimensions } from "react-native"; import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation"; import { useConfiguration } from "../utils"; import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks"; import { isBottomTabVisible } from "../../Screen/navigationHandler"; import { useSafeAreaFrame, useSafeAreaInsets, } from "react-native-safe-area-context"; import { isAndroidPlatform, isAndroidVersionAtLeast, } from "@applicaster/zapp-react-native-utils/reactUtils"; import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight"; import { PROGRESS_BAR_HEIGHT } from "./utils"; import { useIsTablet as getIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks"; import { useAppSelector } from "@applicaster/zapp-react-native-redux"; export type ModalAnimationContextT = { yTranslate: React.MutableRefObject>; offsetAnimatedValueRef: React.MutableRefObject; offset: React.MutableRefObject; heightAboveMinimised: number; gestureTranslationRef: React.MutableRefObject; minimisedHeight: number; }; export const ReactContext = React.createContext({ yTranslate: React.createRef(), offsetAnimatedValueRef: React.createRef(), offset: React.createRef(), heightAboveMinimised: 0, gestureTranslationRef: React.createRef(), minimisedHeight: 60, }); const SAFE_AREA_BREAKING_API_VERSION = 35; export const isOldAndroidDevice = isAndroidPlatform() && !isAndroidVersionAtLeast(SAFE_AREA_BREAKING_API_VERSION); const bottomTabBarHeight = getTabBarHeight(); const Provider = ({ children }: { children: React.ReactNode }) => { const { height } = Dimensions.get("window"); const yTranslate = React.useRef( new Animated.Value(height).interpolate({ inputRange: [0, height], outputRange: [0, height], }) ); const { minimised_height: minimisedHeight } = useConfiguration(); const { videoModalState: { visible, mode }, currentRoute, screenData, } = useNavigation(); const isTabletPortrait = useAppSelector( (state) => state.appData.isTabletPortrait ); const plugins = usePlugins(); const bottomTabsVisible = isBottomTabVisible( currentRoute, screenData, plugins ); const frame = useSafeAreaFrame(); const insets = useSafeAreaInsets(); const [heightAboveMinimised, setHeightAboveMinimised] = React.useState(0); // memoizing heightAboveMinimised value const offset = React.useRef(heightAboveMinimised); // Used for memoizing modal y position after start/end of transition const offsetAnimatedValueRef = React.useRef( new Animated.Value(-offset.current) ); // Used for gesture handling const gestureTranslationRef = React.useRef(new Animated.Value(0)); const videoModalStateRef = React.useRef({ visible, mode }); React.useEffect(() => { videoModalStateRef.current = { visible, mode }; }, [visible, mode]); const translateY = useMemo(() => { const maxRange = heightAboveMinimised; const combined: Animated.AnimatedAddition = Animated.add( offsetAnimatedValueRef.current, gestureTranslationRef.current ); return combined.interpolate({ inputRange: [0, maxRange], outputRange: [0, maxRange], extrapolate: "clamp", }); }, [visible, heightAboveMinimised]); offset.current = heightAboveMinimised; yTranslate.current = translateY; React.useEffect(() => { const collapsedHeight = minimisedHeight + (bottomTabsVisible ? bottomTabBarHeight : 0) + (isOldAndroidDevice ? 0 : insets.bottom) + // insets.bottom is added to properly display docked modal PROGRESS_BAR_HEIGHT; const heightAboveMinimised = frame.height - collapsedHeight; const isLandscape = frame.width > frame.height; const isTablet = getIsTablet(); const shouldIgnoreLandscape = isTablet ? isTabletPortrait : true; if ( heightAboveMinimised !== offset.current && videoModalStateRef.current.mode !== "PIP" && videoModalStateRef.current.mode !== "FULLSCREEN" ) { if (isLandscape && shouldIgnoreLandscape) return; setHeightAboveMinimised(heightAboveMinimised); offset.current = heightAboveMinimised; } }, [frame.height, insets.bottom, bottomTabsVisible, minimisedHeight]); return ( ({ yTranslate, offsetAnimatedValueRef, offset, heightAboveMinimised, minimisedHeight, gestureTranslationRef, }), [minimisedHeight, heightAboveMinimised] )} > {children} ); }; export const withModalAnimationProvider = (Component) => { const WithProvider = (props) => { return ( ); }; return WithProvider; };