import React from "react"; import { last } from "ramda"; import { StyleSheet, View } from "react-native"; import { findMenuPlugin, getNavigationProps, getPathAttributes, } from "@applicaster/zapp-react-native-utils/navigationUtils"; import { useIsScreenActive, useNavigation, } from "@applicaster/zapp-react-native-utils/reactHooks"; import { noop } from "@applicaster/zapp-react-native-utils/functionUtils"; import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks"; import { useNavbarState, useScreenBackgroundColor, } from "@applicaster/zapp-react-native-utils/reactHooks/screen"; import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers"; import { NavBarContainer } from "../../Layout/TV/NavBarContainer"; import { ScreenResolver } from "../../ScreenResolver"; import { useInitialFocus, useAfterPaint } from "./hooks"; import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils"; import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils"; import { FreezeWithCallback } from "../../FreezeWithCallback"; const styles = StyleSheet.create({ container: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, }, }); type Components = { NavBar: React.ComponentType; Background: React.ComponentType; }; type Props = { route: string; Components: Components; }; const getActiveRiver = ({ screenId, screenType, routeState, rivers, fallbackActiveRiver, }) => { if (rivers[screenId]) { if (screenType === "hooks") { const navigations = routeState?.state?.entry?.payload?.navigations; if (navigations) { return routeState.state.entry.payload; } } return routeState?.state?.screen; } // screenId is not presented into rivers, use fallback instead return fallbackActiveRiver; }; const getNavigations = ({ screenId, screenType, routeState, rivers, fallbackNavigations, }) => { if (rivers[screenId]) { // river presents if (screenType === "hooks") { const navigations = routeState?.state?.entry?.payload?.navigations; if (navigations) { return navigations; } } return routeState?.state?.screen?.navigations; } // screenId is not presented into rivers, use fallback instead return fallbackNavigations; }; const onRelease = () => { focusManager.setInitialFocus(); }; export const Screen = ({ route, Components }: Props) => { if (isNilOrEmpty(route)) { throw Error("Required props: route is missing"); } const navigator = useNavigation(); const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]); const pathAttributes = getPathAttributes({ pathname: route }); const routeState = navigator.getStackForPathname(route); const { screenType, screenId } = last(pathAttributes); const backgroundColor = useScreenBackgroundColor(screenId); useInitialFocus(); const activeRiver = getActiveRiver({ screenId, screenType, routeState, rivers, fallbackActiveRiver: navigator.activeRiver, }); const navigationProps = getNavigationProps({ navigator: { // @ts-ignore activeRiver, // @ts-ignore screenTitle: routeState.state.entry?.title || routeState.screen?.name, }, category: "menu", }); const navigations = getNavigations({ screenId, screenType, routeState, rivers, fallbackNavigations: navigator.activeRiver.navigations, }); const menuPlugin = findMenuPlugin(navigations, plugins); const NavBar = (Components.NavBar || menuPlugin.module) as React.ComponentType; const isPlayer = isPlayerPlugin(routeState); const { visible: isNavBarVisible } = useNavbarState(); const screenData = screenType === "hooks" || isPlayer ? routeState?.state?.entry : routeState?.state?.screen; const isScreenActive = useIsScreenActive(); // We need to render menu first and then proceed with screen content, // otherwise screen will stay black until everything is loaded and screen // rendering put huge load the CPU pushing rendering even further. // With this approach, menu will be rendered immediately and screen content // will be rendered after paint, which makes it more responsive and prevents black screen. const isContentReady = useAfterPaint(); return ( {isContentReady ? ( ) : null} ); };