This commit is contained in:
Zhiyuan Zheng 2021-05-23 23:19:37 +02:00
parent 61459cd2d2
commit f8366bb777
5 changed files with 75 additions and 90 deletions

View File

@ -12,21 +12,7 @@ import React, {
useReducer
} from 'react'
import FastImage from 'react-native-fast-image'
import EmojisContext, {
EmojisAction,
EmojisState
} from './Emojis/helpers/EmojisContext'
const emojisReducer = (state: EmojisState, action: EmojisAction) => {
switch (action.type) {
case 'activate':
return { ...state, active: action.payload }
case 'load':
return { ...state, emojis: action.payload }
case 'shortcode':
return { ...state, shortcode: action.payload }
}
}
import EmojisContext, { emojisReducer } from './Emojis/helpers/EmojisContext'
const prefetchEmojis = (
sortedEmojis: { title: string; data: Mastodon.Emoji[][] }[],

View File

@ -27,4 +27,15 @@ type ContextType = {
}
const EmojisContext = createContext<ContextType>({} as ContextType)
export const emojisReducer = (state: EmojisState, action: EmojisAction) => {
switch (action.type) {
case 'activate':
return { ...state, active: action.payload }
case 'load':
return { ...state, emojis: action.payload }
case 'shortcode':
return { ...state, shortcode: action.payload }
}
}
export default EmojisContext

View File

@ -3,7 +3,7 @@ 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 { forEach, groupBy, sortBy } from 'lodash'
import { chunk, forEach, groupBy, sortBy } from 'lodash'
import React, {
useCallback,
useContext,
@ -28,23 +28,26 @@ 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'
const prefetchEmojis = (
sortedEmojis: { title: string; data: Mastodon.Emoji[] }[],
sortedEmojis: NonNullable<ComposeState['emoji']['emojis']>,
reduceMotionEnabled: boolean
) => {
const prefetches: { uri: string }[] = []
let requestedIndex = 0
sortedEmojis.forEach(sorted => {
sorted.data.forEach(emoji => {
if (requestedIndex > 40) {
return
}
prefetches.push({
uri: reduceMotionEnabled ? emoji.static_url : emoji.url
sorted.data.forEach(emojis =>
emojis.forEach(emoji => {
if (requestedIndex > 40) {
return
}
prefetches.push({
uri: reduceMotionEnabled ? emoji.static_url : emoji.url
})
requestedIndex++
})
requestedIndex++
})
)
})
try {
FastImage.preload(prefetches)
@ -90,10 +93,11 @@ const ComposeRoot = React.memo(
const { data: emojisData } = useEmojisQuery({})
useEffect(() => {
if (emojisData && emojisData.length) {
let sortedEmojis: { title: string; data: Mastodon.Emoji[] }[] = []
let sortedEmojis: { title: string; data: Mastodon.Emoji[][] }[] = []
forEach(
groupBy(sortBy(emojisData, ['category', 'shortcode']), 'category'),
(value, key) => sortedEmojis.push({ title: key, data: value })
(value, key) =>
sortedEmojis.push({ title: key, data: chunk(value, 5) })
)
composeDispatch({
type: 'emoji',

View File

@ -1,15 +1,8 @@
import analytics from '@components/analytics'
import haptics from '@components/haptics'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, {
RefObject,
useCallback,
useContext,
useEffect,
useMemo
} from 'react'
import React, { RefObject, useCallback, useContext, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import {
AccessibilityInfo,
@ -25,52 +18,15 @@ import validUrl from 'valid-url'
import updateText from '../../updateText'
import ComposeContext from '../../utils/createContext'
const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
const { t } = useTranslation()
const { reduceMotionEnabled } = useAccessibility()
const { composeState, composeDispatch } = useContext(ComposeContext)
const onPress = useCallback(() => {
analytics('compose_emoji_add')
updateText({
composeState,
composeDispatch,
newText: `:${emoji.shortcode}:`,
type: 'emoji'
})
haptics('Light')
}, [composeState])
const children = useMemo(() => {
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
if (validUrl.isHttpsUri(uri)) {
return (
<FastImage
accessibilityLabel={t('common:customEmoji.accessibilityLabel', {
emoji: emoji.shortcode
})}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri: reduceMotionEnabled ? emoji.static_url : emoji.url }}
style={styles.emoji}
/>
)
} else {
return null
}
}, [])
return (
<Pressable key={emoji.shortcode} onPress={onPress} children={children} />
)
}
export interface Props {
accessibleRefEmojis: RefObject<SectionList>
}
const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
const { composeState } = useContext(ComposeContext)
const { composeState, composeDispatch } = useContext(ComposeContext)
const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme()
const { t } = useTranslation()
useEffect(() => {
const tagEmojis = findNodeHandle(accessibleRefEmojis.current)
@ -86,21 +42,49 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
[]
)
const emojiList = useCallback(
section =>
section.data.map((emoji: Mastodon.Emoji) => (
<SingleEmoji key={emoji.shortcode} emoji={emoji} />
)),
[]
)
const listItem = useCallback(
({ section, index }) =>
index === 0 ? (
<View key={section.title} style={styles.emojis}>
{emojiList(section)}
({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
return (
<View key={index} style={styles.emojis}>
{item.map(emoji => {
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
if (validUrl.isHttpsUri(uri)) {
return (
<Pressable
key={emoji.shortcode}
onPress={() => {
updateText({
composeState,
composeDispatch,
newText: `:${emoji.shortcode}:`,
type: 'emoji'
})
haptics('Light')
}}
>
<FastImage
accessibilityLabel={t(
'common:customEmoji.accessibilityLabel',
{
emoji: emoji.shortcode
}
)}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri }}
style={styles.emoji}
/>
</Pressable>
)
} else {
return null
}
})}
</View>
) : null,
[]
)
},
[composeState]
)
return (
@ -111,7 +95,7 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
horizontal
keyboardShouldPersistTaps='always'
sections={composeState.emoji.emojis || []}
keyExtractor={item => item.shortcode}
keyExtractor={item => item[0].shortcode}
renderSectionHeader={listHeader}
renderItem={listItem}
windowSize={2}

View File

@ -40,7 +40,7 @@ export type ComposeState = {
}
emoji: {
active: boolean
emojis: { title: string; data: Mastodon.Emoji[] }[] | undefined
emojis: { title: string; data: Mastodon.Emoji[][] }[] | undefined
}
poll: {
active: boolean