tooot/src/screens/Compose/Root/Footer/Emojis.tsx

162 lines
5.0 KiB
TypeScript

import haptics from '@components/haptics'
import CustomText from '@components/Text'
import { useAppDispatch } from '@root/store'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { countInstanceEmoji } from '@utils/slices/instancesSlice'
import { getSettingsStaticEmoji } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { RefObject, useCallback, useContext, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import {
AccessibilityInfo,
findNodeHandle,
Image,
Pressable,
SectionList,
View
} from 'react-native'
import FastImage from 'react-native-fast-image'
import { useSelector } from 'react-redux'
import validUrl from 'valid-url'
import updateText from '../../updateText'
import ComposeContext from '../../utils/createContext'
export interface Props {
accessibleRefEmojis: RefObject<SectionList>
}
const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
const { composeState, composeDispatch } = useContext(ComposeContext)
const { reduceMotionEnabled } = useAccessibility()
const { colors } = useTheme()
const { t } = useTranslation()
const dispatch = useAppDispatch()
const staticEmoji = useSelector(getSettingsStaticEmoji)
useEffect(() => {
const tagEmojis = findNodeHandle(accessibleRefEmojis.current)
if (composeState.emoji.active) {
tagEmojis && AccessibilityInfo.setAccessibilityFocus(tagEmojis)
}
}, [composeState.emoji.active])
const listItem = useCallback(
({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
return (
<View
key={index}
style={{
flex: 1,
flexWrap: 'wrap',
marginTop: StyleConstants.Spacing.M,
marginLeft: StyleConstants.Spacing.M
}}
>
{item.map(emoji => {
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
if (validUrl.isHttpsUri(uri)) {
return (
<Pressable
key={emoji.shortcode}
onPress={() => {
haptics('Light')
updateText({
composeState,
composeDispatch,
newText: `:${emoji.shortcode}:`,
type: 'emoji'
})
dispatch(countInstanceEmoji(emoji))
}}
>
{staticEmoji ? (
<Image
accessibilityLabel={t(
'common:customEmoji.accessibilityLabel',
{
emoji: emoji.shortcode
}
)}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri }}
style={{
width: 36,
height: 36,
padding: StyleConstants.Spacing.S,
margin: StyleConstants.Spacing.S
}}
/>
) : (
<FastImage
accessibilityLabel={t(
'common:customEmoji.accessibilityLabel',
{
emoji: emoji.shortcode
}
)}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri }}
style={{
width: 36,
height: 36,
padding: StyleConstants.Spacing.S,
margin: StyleConstants.Spacing.S
}}
/>
)}
</Pressable>
)
} else {
return null
}
})}
</View>
)
},
[composeState]
)
return (
<View
style={{
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-around',
height: 280
}}
>
<SectionList
accessible
ref={accessibleRefEmojis}
horizontal
keyboardShouldPersistTaps='always'
sections={composeState.emoji.emojis || []}
keyExtractor={item => item[0].shortcode}
renderSectionHeader={({ section: { title } }) => (
<CustomText
fontStyle='S'
style={{
position: 'absolute',
left: StyleConstants.Spacing.L,
color: colors.secondary
}}
>
{title}
</CustomText>
)}
renderItem={listItem}
windowSize={2}
/>
</View>
)
}
export default React.memo(ComposeEmojis, () => true)