import { HeaderTitleView } from '@Components/HeaderTitleView'; import { IoniconsHeaderButton } from '@Components/IoniconsHeaderButton'; import { AppStateEventType, AppStateType, TabletModeChangeData, } from '@Lib/application_state'; import { useHasEditor, useIsLocked } from '@Lib/snjs_helper_hooks'; import { ScreenStatus } from '@Lib/status_manager'; import { CompositeNavigationProp, RouteProp } from '@react-navigation/native'; import { createStackNavigator, StackNavigationProp, } from '@react-navigation/stack'; import { Compose } from '@Screens/Compose/Compose'; import { Root } from '@Screens/Root'; import { SCREEN_COMPOSE, SCREEN_NOTES, SCREEN_VIEW_PROTECTED_NOTE, } from '@Screens/screens'; import { MainSideMenu } from '@Screens/SideMenu/MainSideMenu'; import { NoteSideMenu } from '@Screens/SideMenu/NoteSideMenu'; import { ViewProtectedNote } from '@Screens/ViewProtectedNote/ViewProtectedNote'; import { ICON_MENU } from '@Style/icons'; import { ThemeService } from '@Style/theme_service'; import { getDefaultDrawerWidth } from '@Style/utils'; import React, { useCallback, useContext, useEffect, useRef, useState, } from 'react'; import { Dimensions, Keyboard, ScaledSize } from 'react-native'; import DrawerLayout, { DrawerState, } from 'react-native-gesture-handler/DrawerLayout'; import { HeaderButtons, Item } from 'react-navigation-header-buttons'; import { ThemeContext } from 'styled-components'; import { HeaderTitleParams } from './App'; import { ApplicationContext } from './ApplicationContext'; import { ModalStackNavigationProp } from './ModalStack'; type AppStackNavigatorParamList = { [SCREEN_NOTES]: HeaderTitleParams; [SCREEN_COMPOSE]: HeaderTitleParams | undefined; [SCREEN_VIEW_PROTECTED_NOTE]: { onPressView: () => void; }; }; export type AppStackNavigationProp< T extends keyof AppStackNavigatorParamList > = { navigation: CompositeNavigationProp< ModalStackNavigationProp<'AppStack'>['navigation'], StackNavigationProp >; route: RouteProp; }; const AppStack = createStackNavigator(); export const AppStackComponent = ( props: ModalStackNavigationProp<'AppStack'> ) => { // Context const application = useContext(ApplicationContext); const theme = useContext(ThemeContext); const [isLocked] = useIsLocked(); const [hasEditor] = useHasEditor(); // State const [dimensions, setDimensions] = useState(() => Dimensions.get('window')); const [isInTabletMode, setIsInTabletMode] = useState( () => application?.getAppState().isInTabletMode ); const [notesStatus, setNotesStatus] = useState(); const [composeStatus, setComposeStatus] = useState(); const [noteDrawerOpen, setNoteDrawerOpen] = useState(false); // Ref const drawerRef = useRef(null); const noteDrawerRef = useRef(null); useEffect(() => { const removeObserver = application ?.getAppState() .addStateChangeObserver(event => { if (event === AppStateType.EditorClosed) { noteDrawerRef.current?.closeDrawer(); if (!isInTabletMode && props.navigation.canGoBack()) { props.navigation.popToTop(); } } }); return removeObserver; }, [application, props.navigation, isInTabletMode]); useEffect(() => { const removeObserver = application ?.getStatusManager() .addHeaderStatusObserver(messages => { setNotesStatus(messages[SCREEN_NOTES]); setComposeStatus(messages[SCREEN_COMPOSE]); }); return removeObserver; }, [application, isInTabletMode]); useEffect(() => { const updateDimensions = ({ window }: { window: ScaledSize }) => { setDimensions(window); }; Dimensions.addEventListener('change', updateDimensions); return () => Dimensions.removeEventListener('change', updateDimensions); }, []); useEffect(() => { const remoteTabletModeSubscription = application ?.getAppState() .addStateEventObserver((event, data) => { if (event === AppStateEventType.TabletModeChange) { const eventData = data as TabletModeChangeData; if (eventData.new_isInTabletMode && !eventData.old_isInTabletMode) { setIsInTabletMode(true); } else if ( !eventData.new_isInTabletMode && eventData.old_isInTabletMode ) { setIsInTabletMode(false); } } }); return remoteTabletModeSubscription; }, [application]); const handleDrawerStateChange = useCallback( (newState: DrawerState, drawerWillShow: boolean) => { if (newState !== 'Idle' && drawerWillShow) { application?.getAppState().onDrawerOpen(); } }, [application] ); return ( !isLocked && } > setNoteDrawerOpen(true)} onDrawerClose={() => setNoteDrawerOpen(false)} drawerPosition={'right'} drawerType="slide" drawerLockMode={hasEditor ? 'unlocked' : 'locked-closed'} renderNavigationView={() => hasEditor && ( ) } > ({ headerStyle: { backgroundColor: theme.stylekitContrastBackgroundColor, }, headerTintColor: theme.stylekitInfoColor, headerTitle: ({ children }) => { return ; }, })} initialRouteName={SCREEN_NOTES} > ({ title: 'All notes', headerTitle: ({ children }) => { const screenStatus = isInTabletMode ? composeStatus || notesStatus : notesStatus; const title = route.params?.title ?? (children || ''); const subtitle = [screenStatus?.status, route.params?.subTitle] .filter(x => !!x) .join(' • '); return ( ); }, headerLeft: () => ( { Keyboard.dismiss(); drawerRef.current?.openDrawer(); }} /> ), headerRight: () => isInTabletMode && hasEditor && ( { Keyboard.dismiss(); noteDrawerRef.current?.openDrawer(); }} /> ), })} component={Root} /> ({ headerTitle: ({ children }) => { return ( ); }, headerRight: () => !isInTabletMode && ( { Keyboard.dismiss(); noteDrawerRef.current?.openDrawer(); }} /> ), })} component={Compose} /> ({ title: 'View Protected Note', })} component={ViewProtectedNote} /> ); };