import ComponentSeparator from '@components/Separator' import { useEmojisQuery } from '@utils/queryHooks/emojis' import { useSearchQuery } from '@utils/queryHooks/search' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import { chunk, forEach, groupBy, sortBy } from 'lodash' import React, { useContext, useEffect, useMemo, useRef } from 'react' import { AccessibilityInfo, findNodeHandle, FlatList, StyleSheet, View } from 'react-native' import { Circle } from 'react-native-animated-spinkit' import ComposeActions from './Root/Actions' import ComposePosting from './Posting' import ComposeRootFooter from './Root/Footer' import ComposeRootHeader from './Root/Header' import ComposeRootSuggestion from './Root/Suggestion' import ComposeContext from './utils/createContext' import ComposeDrafts from './Root/Drafts' import FastImage from 'react-native-fast-image' import { useAccessibility } from '@utils/accessibility/AccessibilityManager' import { ComposeState } from './utils/types' import { useSelector } from 'react-redux' import { getInstanceConfigurationStatusCharsURL, getInstanceFrequentEmojis } from '@utils/slices/instancesSlice' import { useTranslation } from 'react-i18next' const prefetchEmojis = ( sortedEmojis: NonNullable, reduceMotionEnabled: boolean ) => { const prefetches: { uri: string }[] = [] let requestedIndex = 0 sortedEmojis.forEach(sorted => { sorted.data.forEach(emojis => emojis.forEach(emoji => { if (requestedIndex > 40) { return } prefetches.push({ uri: reduceMotionEnabled ? emoji.static_url : emoji.url }) requestedIndex++ }) ) }) try { FastImage.preload(prefetches) } catch {} } export let instanceConfigurationStatusCharsURL = 23 const ComposeRoot = React.memo( () => { const { reduceMotionEnabled } = useAccessibility() const { colors } = useTheme() instanceConfigurationStatusCharsURL = useSelector( getInstanceConfigurationStatusCharsURL, () => true ) const accessibleRefDrafts = useRef(null) const accessibleRefAttachments = useRef(null) const accessibleRefEmojis = useRef(null) useEffect(() => { const tagDrafts = findNodeHandle(accessibleRefDrafts.current) tagDrafts && AccessibilityInfo.setAccessibilityFocus(tagDrafts) }, [accessibleRefDrafts.current]) const { composeState, composeDispatch } = useContext(ComposeContext) const { isFetching, data, refetch } = useSearchQuery({ type: composeState.tag?.type === 'accounts' || composeState.tag?.type === 'hashtags' ? composeState.tag.type : undefined, term: composeState.tag?.text.substring(1), options: { enabled: false } }) useEffect(() => { if ( (composeState.tag?.type === 'accounts' || composeState.tag?.type === 'hashtags') && composeState.tag?.text ) { refetch() } }, [composeState.tag]) const { t } = useTranslation() const { data: emojisData } = useEmojisQuery({}) const frequentEmojis = useSelector(getInstanceFrequentEmojis, () => true) useEffect(() => { if (emojisData && emojisData.length) { const sortedEmojis: { title: string data: Pick[][] }[] = [] forEach( groupBy(sortBy(emojisData, ['category', 'shortcode']), 'category'), (value, key) => sortedEmojis.push({ title: key, data: chunk(value, 5) }) ) if (frequentEmojis.length) { sortedEmojis.unshift({ title: t('componentEmojis:frequentUsed'), data: chunk( frequentEmojis.map(e => e.emoji), 5 ) }) } composeDispatch({ type: 'emoji', payload: { ...composeState.emoji, emojis: sortedEmojis } }) prefetchEmojis(sortedEmojis, reduceMotionEnabled) } }, [emojisData, reduceMotionEnabled]) const listEmpty = useMemo(() => { if (isFetching) { return ( ) } }, [isFetching]) return ( ( )} ListEmptyComponent={listEmpty} keyboardShouldPersistTaps='always' ListHeaderComponent={ComposeRootHeader} ListFooterComponent={() => ( )} ItemSeparatorComponent={ComponentSeparator} // @ts-ignore data={data ? data[composeState.tag?.type] : undefined} keyExtractor={() => Math.random().toString()} /> ) }, () => true ) const styles = StyleSheet.create({ base: { flex: 1 }, contentView: { flex: 1 }, loading: { flex: 1, alignItems: 'center' } }) export default ComposeRoot