import { useFocusEffect } from '@react-navigation/native'; import { StackNavigationProp } from '@react-navigation/stack'; import { Platform } from '@unimodules/core'; import * as Contacts from 'expo-contacts'; import React from 'react'; import { RefreshControl, StyleSheet, Text, View } from 'react-native'; import HeaderIconButton, { HeaderContainerRight } from '../../components/HeaderIconButton'; import usePermissions from '../../utilities/usePermissions'; import { useResolvedValue } from '../../utilities/useResolvedValue'; import * as ContactUtils from './ContactUtils'; import ContactsList from './ContactsList'; type StackParams = { ContactDetail: { id: string }; }; type Props = { navigation: StackNavigationProp; }; const CONTACT_PAGE_SIZE = 500; export default function ContactsScreen({ navigation }: Props) { const [isAvailable, error] = useResolvedValue(Contacts.isAvailableAsync); const [permission] = usePermissions(Contacts.requestPermissionsAsync); const warning = React.useMemo(() => { if (error) { return `An unknown error occurred while checking the API availability: ${error.message}`; } else if (isAvailable === null) { return 'Checking availability...'; } else if (isAvailable === false) { return 'Contacts API is not available on this platform.'; } else if (!permission) { return 'Contacts permission has not been granted for this app. Grant permission in the Settings app to continue.'; } else if (permission) { return null; } return 'Pending user permission...'; }, [error, permission, isAvailable]); if (warning) { return ( {warning} ); } return ; } function ContactsView({ navigation }: Props) { let rawContacts: Record = {}; const [contacts, setContacts] = React.useState([]); const [hasNextPage, setHasNextPage] = React.useState(true); const [refreshing, setRefreshing] = React.useState(false); const onPressItem = React.useCallback( (id: string) => { navigation.navigate('ContactDetail', { id }); }, [navigation] ); const loadAsync = async (event: { distanceFromEnd?: number } = {}, restart = false) => { if (!hasNextPage || refreshing || Platform.OS === 'web') { return; } setRefreshing(true); const pageOffset = restart ? 0 : contacts.length || 0; const pageSize = restart ? Math.max(pageOffset, CONTACT_PAGE_SIZE) : CONTACT_PAGE_SIZE; const payload = await Contacts.getContactsAsync({ fields: [Contacts.Fields.Name], sort: Contacts.SortTypes.LastName, pageSize, pageOffset, }); const { data: nextContacts } = payload; if (restart) { rawContacts = {}; } for (const contact of nextContacts) { rawContacts[contact.id] = contact; } setContacts(Object.values(rawContacts)); setHasNextPage(payload.hasNextPage); setRefreshing(false); }; const onFocus = React.useCallback(() => { loadAsync(); }, []); useFocusEffect(onFocus); return ( loadAsync({}, true)} /> } data={contacts} onPressItem={onPressItem} onEndReached={loadAsync} /> ); } const styles = StyleSheet.create({ button: { marginVertical: 10, }, permissionContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, contactRow: { marginBottom: 12, }, }); ContactsScreen.navigationOptions = () => { return { title: 'Contacts', headerRight: () => ( { const randomContact = { note: 'Likes expo...' } as Contacts.Contact; ContactUtils.presentNewContactFormAsync({ contact: randomContact }); }} /> ), }; };