import * as React from "react"; import { View, StyleSheet } from "react-native"; import * as R from "ramda"; import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext"; import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation"; import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils"; import { useCurrentScreenData, useNavbarState, } from "@applicaster/zapp-react-native-utils/reactHooks/screen"; import { useTheme } from "@applicaster/zapp-react-native-utils/theme"; import { useScreenConfiguration } from "../../River/useScreenConfiguration"; import { findMenuPlugin, getNavigationProps, routeIsPlayerScreen, } from "@applicaster/zapp-react-native-utils/navigationUtils"; import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils"; import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks"; import { NavBarContainer } from "./NavBarContainer"; type ComponentsExtraProps = { NavBar?: Record; }; type Props = { ComponentsExtraProps?: ComponentsExtraProps; NavBar: React.ComponentType; children: React.ReactNode; }; function displayFullScreen({ currentRoute, screenData }) { const shouldHookBeFullScreen = screenData?.hookPlugin?.module?.presentFullScreen; return ( routeIsPlayerScreen(currentRoute) || !!screenData?.general?.present_full_screen || !!shouldHookBeFullScreen ); } const styles = StyleSheet.create({ container: { flex: 1, height: "100%", width: "100%" }, }); const isTVOS = isApplePlatform(); // eslint-disable-next-line react/display-name export const ScreenContainer = React.memo(function ScreenContainer({ children, ComponentsExtraProps, NavBar, }: Props) { const { screenMarginBottom, resetScreenLayout } = React.useContext(ScreenLayoutContext); const { currentRoute, screenData } = useNavigation(); const screen = useCurrentScreenData(); const { marginBottom, backgroundColor, paddingTop, paddingBottom } = useScreenConfiguration(screen?.id); const theme = useTheme(); const getThemeValue = React.useCallback(R.propOr(0, R.__, theme), [theme]); React.useEffect(() => { resetScreenLayout(); }, [currentRoute]); const fullscreen = React.useCallback( displayFullScreen({ currentRoute, screenData }), [currentRoute, screenData] ); const themeStyles = React.useMemo( () => fullscreen ? {} : { marginBottom: ifEmptyUseFallback(marginBottom, screenMarginBottom), backgroundColor: ifEmptyUseFallback(backgroundColor, "transparent"), paddingTop: ifEmptyUseFallback( paddingTop, getThemeValue("component_padding_top") ), paddingBottom: ifEmptyUseFallback( paddingBottom, getThemeValue("component_padding_bottom") ), }, [ fullscreen, screenMarginBottom, marginBottom, backgroundColor, paddingTop, paddingBottom, ] ); const viewStyles = React.useMemo( () => [styles.container, themeStyles], [themeStyles] ); const navigator = useNavigation(); const { activeRiver } = navigator; const { title, visible } = useNavbarState(); const { plugins = [] } = usePickFromState([ "appState", "remoteConfigurations", "plugins", ]); const navigationProps = getNavigationProps({ navigator, title, category: "menu", }); const menuPlugin = React.useMemo( () => findMenuPlugin(activeRiver?.navigations, plugins), [activeRiver?.navigations] ); const NavBarComponent = React.useMemo( () => NavBar || (menuPlugin.module as React.ComponentType), [] ); // 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 [navBarReady, setNavBarReady] = React.useState(false); const navBarContainer = ( ); return ( <> {!isTVOS ? navBarContainer : null} {navBarReady ? ( /** Need to re-mount this component on each navigation event It's a hack to work around the fact that we don't support correct screen rendering in our navigator (shared currentRoute state) **/ {children} ) : null} {/** Render NavBarContainer over ScreenContainer to let tvOS native focus manager works correctly to focus nav bar items first **/} {isTVOS ? navBarContainer : null} ); });