import Ionicons from '@expo/vector-icons/build/Ionicons'; import Constants from 'expo-constants'; import { Row, View, Text, useExpoTheme } from 'expo-dev-client-components'; import React from 'react'; import { Image, Linking, Platform, StyleSheet, TouchableOpacity } from 'react-native'; type Props = { task: { manifestUrl: string; manifestString: string }; }; function stringOrUndefined(anything: T): string | undefined { if (typeof anything === 'string') { return anything; } return undefined; } function getInfoFromManifest( manifest: NonNullable ): { iconUrl?: string; taskName?: string; sdkVersion?: string; runtimeVersion?: string; isVerified?: boolean; } { if ('metadata' in manifest) { // modern manifest return { iconUrl: undefined, // no icon for modern manifests taskName: manifest.extra?.expoClient?.name, sdkVersion: manifest.extra?.expoClient?.sdkVersion, runtimeVersion: stringOrUndefined(manifest.runtimeVersion), isVerified: (manifest as any).isVerified, }; } else { // no properties for bare manifests return { iconUrl: undefined, taskName: undefined, sdkVersion: undefined, runtimeVersion: undefined, isVerified: undefined, }; } } export function DevMenuTaskInfo({ task }: Props) { const theme = useExpoTheme(); const manifest = task.manifestString ? (JSON.parse(task.manifestString) as typeof Constants.manifest | typeof Constants.manifest2) : null; const manifestInfo = manifest ? getInfoFromManifest(manifest) : null; return ( {manifestInfo?.iconUrl ? ( ) : null} {manifestInfo?.taskName ? manifestInfo.taskName : 'Untitled Experience'} {manifestInfo?.sdkVersion && ( SDK version:{' '} {manifestInfo.sdkVersion} )} {manifestInfo?.runtimeVersion && ( Runtime version:{' '} {manifestInfo.runtimeVersion} )} {!manifestInfo?.isVerified && ( Linking.openURL('https://expo.fyi/unverified-app-expo-go')}> Unverified )} ); } const styles = StyleSheet.create({ taskIcon: { width: 40, height: 40, marginRight: 8, borderRadius: 8, alignSelf: 'center', backgroundColor: 'transparent', }, });