import { HomeFilledIcon, iconSize, RefreshIcon } from '@expo/styleguide-native'; import MaterialCommunityIcons from '@expo/vector-icons/build/MaterialCommunityIcons'; import { Divider, Row, Spacer, useExpoTheme, View } from 'expo-dev-client-components'; import * as Font from 'expo-font'; import React, { Fragment, useContext, useEffect, useRef } from 'react'; import { Clipboard } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ClipboardIcon } from './ClipboardIcon'; import DevMenuBottomSheetContext from './DevMenuBottomSheetContext'; import { DevMenuButton } from './DevMenuButton'; import { DevMenuCloseButton } from './DevMenuCloseButton'; import { DevMenuItem } from './DevMenuItem'; import * as DevMenu from './DevMenuModule'; import { DevMenuOnboarding } from './DevMenuOnboarding'; import { DevMenuServerInfo } from './DevMenuServerInfo'; import { DevMenuTaskInfo } from './DevMenuTaskInfo'; type Props = { task: { manifestUrl: string; manifestString: string }; uuid: string; }; // These are defined in EXVersionManager.m in a dictionary, ordering needs to be // done here. const DEV_MENU_ORDER = [ 'dev-live-reload', 'dev-hmr', 'dev-remote-debug', 'dev-reload', 'dev-perf-monitor', 'dev-inspector', ]; function ThemedMaterialIcon({ name, }: { name: React.ComponentProps['name']; }) { const theme = useExpoTheme(); return ; } const MENU_ITEMS_ICON_MAPPINGS: { [key: string]: React.ReactNode; } = { 'dev-hmr': , 'dev-remote-debug': , 'dev-perf-monitor': , 'dev-inspector': , }; export function DevMenuView({ uuid, task }: Props) { const context = useContext(DevMenuBottomSheetContext); const [enableDevMenuTools, setEnableDevMenuTools] = React.useState(false); const [devMenuItems, setDevMenuItems] = React.useState<{ [key: string]: any }>({}); const [isOnboardingFinished, setIsOnboardingFinished] = React.useState(false); const [isLoaded, setIsLoaded] = React.useState(false); const theme = useExpoTheme(); const insets = useSafeAreaInsets(); const prevUUIDRef = useRef(uuid); useEffect(function didMount() { loadStateAsync(); }, []); useEffect( function loadStateWhenUUIDChanges() { if (prevUUIDRef.current !== uuid) { loadStateAsync(); } prevUUIDRef.current = uuid; }, [uuid] ); async function collapse() { if (context) { await context.collapse(); } } async function collapseAndCloseDevMenuAsync() { await collapse(); await DevMenu.closeAsync(); } async function loadStateAsync() { setIsLoaded(false); const [enableDevMenuTools, devMenuItems, isOnboardingFinished] = await Promise.all([ DevMenu.doesCurrentTaskEnableDevtoolsAsync(), DevMenu.getItemsToShowAsync(), DevMenu.isOnboardingFinishedAsync(), Font.loadAsync({ 'Inter-Black': require('../assets/Inter/Inter-Black.otf'), 'Inter-BlackItalic': require('../assets/Inter/Inter-BlackItalic.otf'), 'Inter-Bold': require('../assets/Inter/Inter-Bold.otf'), 'Inter-BoldItalic': require('../assets/Inter/Inter-BoldItalic.otf'), 'Inter-ExtraBold': require('../assets/Inter/Inter-ExtraBold.otf'), 'Inter-ExtraBoldItalic': require('../assets/Inter/Inter-ExtraBoldItalic.otf'), 'Inter-ExtraLight': require('../assets/Inter/Inter-ExtraLight.otf'), 'Inter-ExtraLightItalic': require('../assets/Inter/Inter-ExtraLightItalic.otf'), 'Inter-Regular': require('../assets/Inter/Inter-Regular.otf'), 'Inter-Italic': require('../assets/Inter/Inter-Italic.otf'), 'Inter-Light': require('../assets/Inter/Inter-Light.otf'), 'Inter-LightItalic': require('../assets/Inter/Inter-LightItalic.otf'), 'Inter-Medium': require('../assets/Inter/Inter-Medium.otf'), 'Inter-MediumItalic': require('../assets/Inter/Inter-MediumItalic.otf'), 'Inter-SemiBold': require('../assets/Inter/Inter-SemiBold.otf'), 'Inter-SemiBoldItalic': require('../assets/Inter/Inter-SemiBoldItalic.otf'), 'Inter-Thin': require('../assets/Inter/Inter-Thin.otf'), 'Inter-ThinItalic': require('../assets/Inter/Inter-ThinItalic.otf'), }), ]); setEnableDevMenuTools(enableDevMenuTools); setDevMenuItems(devMenuItems); setIsOnboardingFinished(isOnboardingFinished); setIsLoaded(true); } function onAppReload() { collapse(); DevMenu.reloadAppAsync(); } async function onCopyTaskUrl() { const { manifestUrl } = task; await collapseAndCloseDevMenuAsync(); Clipboard.setString(manifestUrl); alert(`Copied "${manifestUrl}" to the clipboard!`); } function onGoToHome() { collapse(); DevMenu.goToHomeAsync(); } function onPressDevMenuButton(key: string) { DevMenu.selectItemWithKeyAsync(key); } function onOnboardingFinished() { DevMenu.setOnboardingFinishedAsync(true); setIsOnboardingFinished(true); } const sortedDevMenuItems = Object.keys(devMenuItems).sort( (a, b) => DEV_MENU_ORDER.indexOf(a) - DEV_MENU_ORDER.indexOf(b) ); if (!isLoaded) { return null; } return ( {!isOnboardingFinished ? ( ) : ( } /> {task && task.manifestUrl && ( <> } /> )} } /> {enableDevMenuTools && devMenuItems && ( {sortedDevMenuItems.map((key, i) => { const item = devMenuItems[key]; const { label, isEnabled } = item; return ( {i < sortedDevMenuItems.length - 1 && } ); })} )} )} ); }